]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/listbox.cpp
wxChoice and wxListBox GTK+ changes (wxChoice works, wxListBox still doesn't)
[wxWidgets.git] / src / gtk1 / 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/listbox.h"
16
17 #if wxUSE_LISTBOX
18
19 #include "wx/dynarray.h"
20 #include "wx/utils.h"
21 #include "wx/intl.h"
22 #include "wx/checklst.h"
23 #include "wx/settings.h"
24
25 #if wxUSE_TOOLTIPS
26 #include "wx/tooltip.h"
27 #endif
28
29 #if wxUSE_DRAG_AND_DROP
30 #include "wx/dnd.h"
31 #endif
32
33 #include "gdk/gdk.h"
34 #include "gtk/gtk.h"
35
36 //-----------------------------------------------------------------------------
37 // idle system
38 //-----------------------------------------------------------------------------
39
40 extern void wxapp_install_idle_handler();
41 extern bool g_isIdle;
42
43 //-------------------------------------------------------------------------
44 // conditional compilation
45 //-------------------------------------------------------------------------
46
47 #if (GTK_MINOR_VERSION > 0)
48 #define NEW_GTK_SCROLL_CODE
49 #endif
50
51 //-----------------------------------------------------------------------------
52 // private functions
53 //-----------------------------------------------------------------------------
54
55 #if wxUSE_CHECKLISTBOX
56
57 #define CHECKBOX_STRING "[-] "
58
59 // checklistboxes have "[±] " prepended to their lables, this macro removes it
60 // (NB: 4 below is the length of CHECKBOX_STRING above)
61 //
62 // the argument to it is a "const char *" pointer
63 #define GET_REAL_LABEL(label) ((m_hasCheckBoxes)?(label)+4 : (label))
64
65 #else // !wxUSE_CHECKLISTBOX
66
67 #define GET_REAL_LABEL(label) (label)
68
69 #endif // wxUSE_CHECKLISTBOX
70
71 //-----------------------------------------------------------------------------
72 // data
73 //-----------------------------------------------------------------------------
74
75 extern bool g_blockEventsOnDrag;
76 extern bool g_blockEventsOnScroll;
77 extern wxCursor g_globalCursor;
78
79 static bool g_hasDoubleClicked = FALSE;
80
81 //-----------------------------------------------------------------------------
82 // "button_release_event"
83 //-----------------------------------------------------------------------------
84
85 /* we would normally emit a wxEVT_COMMAND_LISTBOX_DOUBLECLICKED event once
86 a GDK_2BUTTON_PRESS occurs, but this has the particular problem of the
87 listbox keeping the focus until it receives a GDK_BUTTON_RELEASE event.
88 this can lead to race conditions so that we emit the dclick event
89 after the GDK_BUTTON_RELEASE event after the GDK_2BUTTON_PRESS event */
90
91 static gint
92 gtk_listbox_button_release_callback( GtkWidget * WXUNUSED(widget),
93 GdkEventButton * WXUNUSED(gdk_event),
94 wxListBox *listbox )
95 {
96 if (g_isIdle) wxapp_install_idle_handler();
97
98 if (g_blockEventsOnDrag) return FALSE;
99 if (g_blockEventsOnScroll) return FALSE;
100
101 if (!listbox->m_hasVMT) return FALSE;
102
103 if (!g_hasDoubleClicked) return FALSE;
104
105 wxCommandEvent event( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, listbox->GetId() );
106 event.SetEventObject( listbox );
107
108 wxArrayInt aSelections;
109 int count = listbox->GetSelections(aSelections);
110 if ( count > 0 )
111 {
112 event.m_commandInt = aSelections[0] ;
113 event.m_clientData = listbox->GetClientData( event.m_commandInt );
114 wxString str(listbox->GetString(event.m_commandInt));
115 if (!str.IsEmpty()) event.m_commandString = str;
116 }
117 else
118 {
119 event.m_commandInt = -1 ;
120 event.m_commandString.Empty();
121 }
122
123 listbox->GetEventHandler()->ProcessEvent( event );
124
125 return FALSE;
126 }
127
128 //-----------------------------------------------------------------------------
129 // "button_press_event"
130 //-----------------------------------------------------------------------------
131
132 static gint
133 gtk_listbox_button_press_callback( GtkWidget *widget,
134 GdkEventButton *gdk_event,
135 wxListBox *listbox )
136 {
137 if (g_isIdle) wxapp_install_idle_handler();
138
139 if (g_blockEventsOnDrag) return FALSE;
140 if (g_blockEventsOnScroll) return FALSE;
141
142 if (!listbox->m_hasVMT) return FALSE;
143
144 int sel = listbox->GetIndex( widget );
145
146 #if wxUSE_CHECKLISTBOX
147 if ((listbox->m_hasCheckBoxes) && (gdk_event->x < 15) && (gdk_event->type != GDK_2BUTTON_PRESS))
148 {
149 wxCheckListBox *clb = (wxCheckListBox *)listbox;
150
151 clb->Check( sel, !clb->IsChecked(sel) );
152
153 wxCommandEvent event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, listbox->GetId() );
154 event.SetEventObject( listbox );
155 event.SetInt( sel );
156 listbox->GetEventHandler()->ProcessEvent( event );
157 }
158 #endif // wxUSE_CHECKLISTBOX
159
160 /* emit wxEVT_COMMAND_LISTBOX_DOUBLECLICKED later */
161 g_hasDoubleClicked = (gdk_event->type == GDK_2BUTTON_PRESS);
162
163 return FALSE;
164 }
165
166 //-----------------------------------------------------------------------------
167 // "key_press_event"
168 //-----------------------------------------------------------------------------
169
170 #if wxUSE_CHECKLISTBOX
171 static gint
172 gtk_listbox_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxListBox *listbox )
173 {
174 if (g_isIdle) wxapp_install_idle_handler();
175
176 if (g_blockEventsOnDrag) return FALSE;
177
178 if (!listbox->m_hasVMT) return FALSE;
179
180 if (gdk_event->keyval != ' ') return FALSE;
181
182 int sel = listbox->GetIndex( widget );
183
184 wxCheckListBox *clb = (wxCheckListBox *)listbox;
185
186 clb->Check( sel, !clb->IsChecked(sel) );
187
188 wxCommandEvent event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, listbox->GetId() );
189 event.SetEventObject( listbox );
190 event.SetInt( sel );
191 listbox->GetEventHandler()->ProcessEvent( event );
192
193 return FALSE;
194 }
195 #endif // wxUSE_CHECKLISTBOX
196
197 //-----------------------------------------------------------------------------
198 // "select" and "deselect"
199 //-----------------------------------------------------------------------------
200
201 static void gtk_listitem_select_callback( GtkWidget *WXUNUSED(widget), wxListBox *listbox );
202
203 static void gtk_listitem_deselect_callback( GtkWidget *widget, wxListBox *listbox )
204 {
205 gtk_listitem_select_callback( widget, listbox );
206 }
207
208 static void gtk_listitem_select_callback( GtkWidget *WXUNUSED(widget), wxListBox *listbox )
209 {
210 if (g_isIdle) wxapp_install_idle_handler();
211
212 if (!listbox->m_hasVMT) return;
213 if (g_blockEventsOnDrag) return;
214
215 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, listbox->GetId() );
216
217 wxArrayInt aSelections;
218 int n, count = listbox->GetSelections(aSelections);
219 if ( count > 0 )
220 {
221 n = aSelections[0];
222 event.m_clientData = listbox->m_clientData.Item(n);
223 event.m_commandString = listbox->GetString(n);
224 }
225 else
226 {
227 n = -1;
228 }
229
230 event.m_commandInt = n;
231
232 event.SetEventObject( listbox );
233
234 listbox->GetEventHandler()->ProcessEvent( event );
235 }
236
237 //-----------------------------------------------------------------------------
238 // wxListBox
239 //-----------------------------------------------------------------------------
240
241 IMPLEMENT_DYNAMIC_CLASS(wxListBox,wxControl)
242
243 // ----------------------------------------------------------------------------
244 // construction
245 // ----------------------------------------------------------------------------
246
247 wxListBox::wxListBox()
248 {
249 m_list = (GtkList *) NULL;
250 #if wxUSE_CHECKLISTBOX
251 m_hasCheckBoxes = FALSE;
252 #endif // wxUSE_CHECKLISTBOX
253 }
254
255 bool wxListBox::Create( wxWindow *parent, wxWindowID id,
256 const wxPoint &pos, const wxSize &size,
257 int n, const wxString choices[],
258 long style, const wxValidator& validator,
259 const wxString &name )
260 {
261 m_needParent = TRUE;
262 m_acceptsFocus = TRUE;
263
264 if (!PreCreation( parent, pos, size ) ||
265 !CreateBase( parent, id, pos, size, style, validator, name ))
266 {
267 wxFAIL_MSG( wxT("wxListBox creation failed") );
268 return FALSE;
269 }
270
271 m_widget = gtk_scrolled_window_new( (GtkAdjustment*) NULL, (GtkAdjustment*) NULL );
272 if (style & wxLB_ALWAYS_SB)
273 {
274 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
275 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS );
276 }
277 else
278 {
279 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
280 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
281 }
282
283 m_list = GTK_LIST( gtk_list_new() );
284
285 GtkSelectionMode mode = GTK_SELECTION_BROWSE;
286 if (style & wxLB_MULTIPLE)
287 mode = GTK_SELECTION_MULTIPLE;
288 else if (style & wxLB_EXTENDED)
289 mode = GTK_SELECTION_EXTENDED;
290
291 gtk_list_set_selection_mode( GTK_LIST(m_list), mode );
292
293 #ifdef NEW_GTK_SCROLL_CODE
294 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(m_widget), GTK_WIDGET(m_list) );
295 #else
296 gtk_container_add( GTK_CONTAINER(m_widget), GTK_WIDGET(m_list) );
297 #endif
298
299 /* make list scroll when moving the focus down using cursor keys */
300 gtk_container_set_focus_vadjustment(
301 GTK_CONTAINER(m_list),
302 gtk_scrolled_window_get_vadjustment(
303 GTK_SCROLLED_WINDOW(m_widget)));
304
305 gtk_widget_show( GTK_WIDGET(m_list) );
306
307 wxSize newSize = size;
308 if (newSize.x == -1) newSize.x = 100;
309 if (newSize.y == -1) newSize.y = 110;
310 SetSize( newSize.x, newSize.y );
311
312 if ( style & wxLB_SORT )
313 {
314 // this will change DoAppend() behaviour
315 m_strings = new wxSortedArrayString;
316 }
317
318 for (int i = 0; i < n; i++)
319 {
320 m_clientData.Append((wxObject *)NULL);
321
322 DoAppend(choices[i]);
323
324 #if 0
325 wxString str(choices[i]);
326
327 #if wxUSE_CHECKLISTBOX
328 if (m_hasCheckBoxes)
329 {
330 str.Prepend(CHECKBOX_STRING);
331 }
332 #endif // wxUSE_CHECKLISTBOX
333
334 GtkWidget *list_item = gtk_list_item_new_with_label( str.mbc_str() );
335
336 gtk_container_add( GTK_CONTAINER(m_list), list_item );
337
338 gtk_signal_connect( GTK_OBJECT(list_item), "select",
339 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
340
341 if (style & wxLB_MULTIPLE)
342 gtk_signal_connect( GTK_OBJECT(list_item), "deselect",
343 GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback), (gpointer)this );
344
345 gtk_signal_connect( GTK_OBJECT(list_item),
346 "button_press_event",
347 (GtkSignalFunc)gtk_listbox_button_press_callback,
348 (gpointer) this );
349
350 gtk_signal_connect_after( GTK_OBJECT(list_item),
351 "button_release_event",
352 (GtkSignalFunc)gtk_listbox_button_release_callback,
353 (gpointer) this );
354
355 #if wxUSE_CHECKLISTBOX
356 if (m_hasCheckBoxes)
357 {
358 gtk_signal_connect( GTK_OBJECT(list_item),
359 "key_press_event",
360 (GtkSignalFunc)gtk_listbox_key_press_callback,
361 (gpointer)this );
362 }
363 #endif // wxUSE_CHECKLISTBOX
364
365 ConnectWidget( list_item );
366
367 gtk_widget_show( list_item );
368 #endif // 0
369 }
370
371 m_parent->DoAddChild( this );
372
373 PostCreation();
374
375 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOW ) );
376 SetForegroundColour( parent->GetForegroundColour() );
377 SetFont( parent->GetFont() );
378
379 Show( TRUE );
380
381 return TRUE;
382 }
383
384 wxListBox::~wxListBox()
385 {
386 Clear();
387 }
388
389 void wxListBox::DoInsertItems(const wxArrayString& items, int pos)
390 {
391 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
392
393 // code elsewhere supposes we have as many items in m_clientData as items
394 // in the listbox
395 wxASSERT_MSG( m_clientData.GetCount() == (size_t)GetCount(),
396 wxT("bug in client data management") );
397
398 GList *children = m_list->children;
399 int length = g_list_length(children);
400 wxCHECK_RET( pos <= length, wxT("invalid index in wxListBox::InsertItems") );
401
402 // VZ: it seems that GTK 1.0.6 doesn't has a function to insert an item
403 // into a listbox at the given position, this is why we first delete
404 // all items after this position, then append these items and then
405 // reappend back the old ones.
406
407 // VZ: notice that InsertItems knows nothing about sorting, so calling it
408 // from outside (and not from our own Append) is likely to break
409 // everything
410
411 size_t nItems = items.GetCount();
412
413 size_t n; // loop var
414
415 // optimise for this trivial case
416 if ( pos == length )
417 {
418 // no need to do anything complicated
419 for ( n = 0; n < nItems; n++ )
420 {
421 AppendWithoutSorting(items[n]);
422
423 m_clientData.Append((wxObject *)NULL);
424 }
425
426 wxASSERT_MSG( m_clientData.GetCount() == (size_t)GetCount(),
427 wxT("bug in client data management") );
428
429 return;
430 }
431
432 // remove the old items
433 wxArrayString deletedLabels;
434 wxArrayPtrVoid deletedData;
435 #if wxUSE_CHECKLISTBOX
436 wxArrayInt deletedChecks;
437 #endif
438
439 GList *child = g_list_nth( children, pos );
440 for ( n = 0; child != NULL; n++, child = child->next )
441 {
442 // save label
443 GtkBin *bin = GTK_BIN( child->data );
444 GtkLabel *label = GTK_LABEL( bin->child );
445
446 wxString str(GET_REAL_LABEL(label->label),*wxConvCurrent);
447 deletedLabels.Add(str);
448
449 // save data
450 deletedData.Add(m_clientData.Item(n));
451
452 #if wxUSE_CHECKLISTBOX
453 // save check state
454 if ( m_hasCheckBoxes )
455 {
456 deletedChecks.Add(((wxCheckListBox *)this)->IsChecked(pos + n));
457 }
458 #endif // wxUSE_CHECKLISTBOX
459 }
460
461 // don't delete contents, the data will be reappended soon
462 m_clientData.Clear();
463
464 size_t nDeletedCount = n;
465
466 gtk_list_clear_items( m_list, pos, length );
467
468 // now append the new items
469 for ( n = 0; n < nItems; n++ )
470 {
471 AppendWithoutSorting(items[n]);
472
473 m_clientData.Append((wxObject *)NULL);
474 }
475
476 // and append the old items too
477 pos += nItems; // now the indices are shifter
478 for ( n = 0; n < nDeletedCount; n++ )
479 {
480 AppendWithoutSorting(deletedLabels[n]);
481
482 m_clientData.Append((wxObject *)NULL);
483
484 if ( m_clientDataItemsType == ClientData_Object )
485 SetClientObject(n, (wxClientData *)deletedData[n]);
486 else if ( m_clientDataItemsType == ClientData_Void )
487 SetClientData(n, deletedData[n]);
488
489 #if wxUSE_CHECKLISTBOX
490 if ( m_hasCheckBoxes )
491 {
492 ((wxCheckListBox *)this)->Check(pos + n, (bool)deletedChecks[n]);
493 }
494 #endif // wxUSE_CHECKLISTBOX
495 }
496
497 wxASSERT_MSG( m_clientData.GetCount() == (size_t)GetCount(),
498 wxT("bug in client data management") );
499 }
500
501 int wxListBox::DoAppend( const wxString& item )
502 {
503 int index;
504 if ( m_strings )
505 {
506 // need to determine the index
507 index = m_strings->Add(item);
508
509 InsertItems(1, &item, index);
510 }
511 else
512 {
513 // not sorted, just append
514 AppendWithoutSorting(item);
515
516 m_clientData.Append((wxObject *)NULL);
517
518 index = GetCount() - 1;
519 }
520
521 return index;
522 }
523
524 void wxListBox::AppendWithoutSorting( const wxString &item )
525 {
526 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
527
528 GtkWidget *list_item;
529
530 wxString label(item);
531 #if wxUSE_CHECKLISTBOX
532 if (m_hasCheckBoxes)
533 {
534 label.Prepend(CHECKBOX_STRING);
535 }
536 #endif // wxUSE_CHECKLISTBOX
537
538 list_item = gtk_list_item_new_with_label( label.mbc_str() );
539
540 gtk_container_add( GTK_CONTAINER(m_list), list_item );
541
542 gtk_signal_connect( GTK_OBJECT(list_item), "select",
543 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
544
545 if (HasFlag(wxLB_MULTIPLE))
546 gtk_signal_connect( GTK_OBJECT(list_item), "deselect",
547 GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback), (gpointer)this );
548
549 gtk_signal_connect( GTK_OBJECT(list_item),
550 "button_press_event",
551 (GtkSignalFunc)gtk_listbox_button_press_callback,
552 (gpointer) this );
553
554 gtk_signal_connect_after( GTK_OBJECT(list_item),
555 "button_release_event",
556 (GtkSignalFunc)gtk_listbox_button_release_callback,
557 (gpointer) this );
558
559 #if wxUSE_CHECKLISTBOX
560 if (m_hasCheckBoxes)
561 {
562 gtk_signal_connect( GTK_OBJECT(list_item),
563 "key_press_event",
564 (GtkSignalFunc)gtk_listbox_key_press_callback,
565 (gpointer)this );
566 }
567 #endif // wxUSE_CHECKLISTBOX
568
569 gtk_widget_show( list_item );
570
571 ConnectWidget( list_item );
572
573 if (GTK_WIDGET_REALIZED(m_widget))
574 {
575 gtk_widget_realize( list_item );
576 gtk_widget_realize( GTK_BIN(list_item)->child );
577
578 //if (m_widgetStyle) ApplyWidgetStyle();
579 if (m_widgetStyle) {
580 // Apply current widget style to the new list_item
581 gtk_widget_set_style( GTK_WIDGET( list_item ), m_widgetStyle );
582 GtkBin *bin = GTK_BIN( list_item );
583 GtkWidget *label = GTK_WIDGET( bin->child );
584 gtk_widget_set_style( label, m_widgetStyle );
585 }
586
587 #if wxUSE_DRAG_AND_DROP
588 #ifndef NEW_GTK_DND_CODE
589 if (m_dropTarget) m_dropTarget->RegisterWidget( list_item );
590 #endif
591 #endif
592
593 #if wxUSE_TOOLTIPS
594 if (m_tooltip) m_tooltip->Apply( this );
595 #endif
596 }
597 }
598
599 void wxListBox::DoSetItems( const wxArrayString& items,
600 void **clientData)
601 {
602 Clear();
603
604 DoInsertItems(items, 0);
605
606 if ( clientData )
607 {
608 size_t count = items.GetCount();
609 for ( size_t n = 0; n < count; n++ )
610 {
611 SetClientData(n, clientData[n]);
612 }
613 }
614 }
615
616 // ----------------------------------------------------------------------------
617 // client data
618 // ----------------------------------------------------------------------------
619
620 void wxListBox::DoSetClientData( int n, void* clientData )
621 {
622 wxCHECK_RET( m_widget != NULL, wxT("invalid listbox control") );
623
624 wxNode *node = m_clientData.Nth( n );
625 wxCHECK_RET( node, wxT("invalid index in wxListBox::DoSetClientData") );
626
627 node->SetData( (wxObject*) clientData );
628 }
629
630 void* wxListBox::DoGetClientData( int n ) const
631 {
632 wxCHECK_MSG( m_widget != NULL, NULL, wxT("invalid listbox control") );
633
634 wxNode *node = m_clientData.Nth( n );
635 wxCHECK_MSG( node, NULL, wxT("invalid index in wxListBox::DoGetClientData") );
636
637 return node->Data();
638 }
639
640 void wxListBox::DoSetClientObject( int n, wxClientData* clientData )
641 {
642 wxCHECK_RET( m_widget != NULL, wxT("invalid listbox control") );
643
644 wxNode *node = m_clientData.Nth( n );
645 wxCHECK_RET( node, wxT("invalid index in wxListBox::DoSetClientObject") );
646
647 wxClientData *cd = (wxClientData*) node->Data();
648 delete cd;
649
650 node->SetData( (wxObject*) clientData );
651 }
652
653 wxClientData* wxListBox::DoGetClientObject( int n ) const
654 {
655 wxCHECK_MSG( m_widget != NULL, (wxClientData*) NULL, wxT("invalid listbox control") );
656
657 wxNode *node = m_clientData.Nth( n );
658 wxCHECK_MSG( node, (wxClientData *)NULL,
659 wxT("invalid index in wxListBox::DoGetClientObject") );
660
661 return (wxClientData*) node->Data();
662 }
663
664 void wxListBox::Clear()
665 {
666 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
667
668 gtk_list_clear_items( m_list, 0, Number() );
669
670 if ( m_clientDataItemsType == ClientData_Object )
671 m_clientData.DeleteContents(TRUE);
672 m_clientData.Clear();
673
674 if ( m_strings )
675 m_strings->Clear();
676 }
677
678 void wxListBox::Delete( int n )
679 {
680 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
681
682 GList *child = g_list_nth( m_list->children, n );
683
684 wxCHECK_RET( child, wxT("wrong listbox index") );
685
686 GList *list = g_list_append( (GList*) NULL, child->data );
687 gtk_list_remove_items( m_list, list );
688 g_list_free( list );
689
690 wxNode *node = m_clientData.Nth( n );
691 if ( node )
692 {
693 if ( m_clientDataItemsType == ClientData_Object )
694 {
695 wxClientData *cd = (wxClientData*)node->Data();
696 delete cd;
697 }
698
699 m_clientData.DeleteNode( node );
700 }
701
702 if ( m_strings )
703 m_strings->Remove(n);
704 }
705
706 // ----------------------------------------------------------------------------
707 // string list access
708 // ----------------------------------------------------------------------------
709
710 void wxListBox::SetString( int n, const wxString &string )
711 {
712 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
713
714 GList *child = g_list_nth( m_list->children, n );
715 if (child)
716 {
717 GtkBin *bin = GTK_BIN( child->data );
718 GtkLabel *label = GTK_LABEL( bin->child );
719
720 wxString str;
721 #if wxUSE_CHECKLISTBOX
722 if (m_hasCheckBoxes)
723 str += CHECKBOX_STRING;
724 #endif // wxUSE_CHECKLISTBOX
725 str += string;
726
727 gtk_label_set( label, str.mbc_str() );
728 }
729 else
730 {
731 wxFAIL_MSG(wxT("wrong listbox index"));
732 }
733 }
734
735 wxString wxListBox::GetString( int n ) const
736 {
737 wxCHECK_MSG( m_list != NULL, wxT(""), wxT("invalid listbox") );
738
739 GList *child = g_list_nth( m_list->children, n );
740 if (child)
741 {
742 GtkBin *bin = GTK_BIN( child->data );
743 GtkLabel *label = GTK_LABEL( bin->child );
744
745 wxString str = wxString(GET_REAL_LABEL(label->label),*wxConvCurrent);
746
747 return str;
748 }
749
750 wxFAIL_MSG(wxT("wrong listbox index"));
751
752 return wxT("");
753 }
754
755 int wxListBox::GetCount() const
756 {
757 wxCHECK_MSG( m_list != NULL, -1, wxT("invalid listbox") );
758
759 GList *child = m_list->children;
760 int count = 0;
761 while (child)
762 {
763 count++;
764 child = child->next;
765 }
766
767 return count;
768 }
769
770 int wxListBox::FindString( const wxString &item ) const
771 {
772 wxCHECK_MSG( m_list != NULL, -1, wxT("invalid listbox") );
773
774 GList *child = m_list->children;
775 int count = 0;
776 while (child)
777 {
778 GtkBin *bin = GTK_BIN( child->data );
779 GtkLabel *label = GTK_LABEL( bin->child );
780
781 wxString str = wxString(GET_REAL_LABEL(label->label),*wxConvCurrent);
782
783 if (str == item)
784 return count;
785
786 count++;
787 child = child->next;
788 }
789
790 // it's not an error if the string is not found -> no wxCHECK
791
792 return wxNOT_FOUND;
793 }
794
795 // ----------------------------------------------------------------------------
796 // selection
797 // ----------------------------------------------------------------------------
798
799 int wxListBox::GetSelection() const
800 {
801 wxCHECK_MSG( m_list != NULL, -1, wxT("invalid listbox") );
802
803 GList *child = m_list->children;
804 int count = 0;
805 while (child)
806 {
807 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED) return count;
808 count++;
809 child = child->next;
810 }
811 return -1;
812 }
813
814 int wxListBox::GetSelections( wxArrayInt& aSelections ) const
815 {
816 wxCHECK_MSG( m_list != NULL, -1, wxT("invalid listbox") );
817
818 // get the number of selected items first
819 GList *child = m_list->children;
820 int count = 0;
821 for (child = m_list->children; child != NULL; child = child->next)
822 {
823 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED)
824 count++;
825 }
826
827 aSelections.Empty();
828
829 if (count > 0)
830 {
831 // now fill the list
832 aSelections.Alloc(count); // optimization attempt
833 int i = 0;
834 for (child = m_list->children; child != NULL; child = child->next, i++)
835 {
836 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED)
837 aSelections.Add(i);
838 }
839 }
840
841 return count;
842 }
843
844 bool wxListBox::IsSelected( int n ) const
845 {
846 wxCHECK_MSG( m_list != NULL, FALSE, wxT("invalid listbox") );
847
848 GList *target = g_list_nth( m_list->children, n );
849 if (target)
850 {
851 GList *child = m_list->selection;
852 while (child)
853 {
854 if (child->data == target->data) return TRUE;
855 child = child->next;
856 }
857 }
858
859 wxFAIL_MSG(wxT("wrong listbox index"));
860
861 return FALSE;
862 }
863
864 void wxListBox::SetSelection( int n, bool select )
865 {
866 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
867
868 DisableEvents();
869
870 if (select)
871 gtk_list_select_item( m_list, n );
872 else
873 gtk_list_unselect_item( m_list, n );
874
875 EnableEvents();
876 }
877
878 void wxListBox::DoSetFirstItem( int WXUNUSED(n) )
879 {
880 wxFAIL_MSG(wxT("wxListBox::SetFirstItem not implemented"));
881 }
882
883 // ----------------------------------------------------------------------------
884 // helpers
885 // ----------------------------------------------------------------------------
886
887 int wxListBox::GetIndex( GtkWidget *item ) const
888 {
889 if (item)
890 {
891 GList *child = m_list->children;
892 int count = 0;
893 while (child)
894 {
895 if (GTK_WIDGET(child->data) == item) return count;
896 count++;
897 child = child->next;
898 }
899 }
900 return -1;
901 }
902
903 #if wxUSE_TOOLTIPS
904 void wxListBox::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
905 {
906 GList *child = m_list->children;
907 while (child)
908 {
909 gtk_tooltips_set_tip( tips, GTK_WIDGET( child->data ), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
910 child = child->next;
911 }
912 }
913 #endif // wxUSE_TOOLTIPS
914
915 #if wxUSE_DRAG_AND_DROP
916 void wxListBox::SetDropTarget( wxDropTarget *dropTarget )
917 {
918 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
919
920 #ifndef NEW_GTK_DND_CODE
921 if (m_dropTarget)
922 {
923 GList *child = m_list->children;
924 while (child)
925 {
926 m_dropTarget->UnregisterWidget( GTK_WIDGET( child->data ) );
927 child = child->next;
928 }
929 }
930 #endif
931
932 wxWindow::SetDropTarget( dropTarget );
933
934 #ifndef NEW_GTK_DND_CODE
935 if (m_dropTarget)
936 {
937 GList *child = m_list->children;
938 while (child)
939 {
940 m_dropTarget->RegisterWidget( GTK_WIDGET( child->data ) );
941 child = child->next;
942 }
943 }
944 #endif
945 }
946 #endif
947
948 void wxListBox::DisableEvents()
949 {
950 GList *child = m_list->children;
951 while (child)
952 {
953 gtk_signal_disconnect_by_func( GTK_OBJECT(child->data),
954 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
955
956 if (HasFlag(wxLB_MULTIPLE))
957 gtk_signal_disconnect_by_func( GTK_OBJECT(child->data),
958 GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback), (gpointer)this );
959
960 child = child->next;
961 }
962 }
963
964 void wxListBox::EnableEvents()
965 {
966 GList *child = m_list->children;
967 while (child)
968 {
969 gtk_signal_connect( GTK_OBJECT(child->data), "select",
970 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
971
972 if (HasFlag(wxLB_MULTIPLE))
973 gtk_signal_connect( GTK_OBJECT(child->data), "deselect",
974 GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback), (gpointer)this );
975
976 child = child->next;
977 }
978 }
979
980 GtkWidget *wxListBox::GetConnectWidget()
981 {
982 return GTK_WIDGET(m_list);
983 }
984
985 bool wxListBox::IsOwnGtkWindow( GdkWindow *window )
986 {
987 if (wxWindow::IsOwnGtkWindow( window )) return TRUE;
988
989 GList *child = m_list->children;
990 while (child)
991 {
992 GtkWidget *bin = GTK_WIDGET( child->data );
993 if (bin->window == window) return TRUE;
994 child = child->next;
995 }
996
997 return FALSE;
998 }
999
1000 void wxListBox::ApplyWidgetStyle()
1001 {
1002 SetWidgetStyle();
1003
1004 if (m_backgroundColour.Ok())
1005 {
1006 GdkWindow *window = GTK_WIDGET(m_list)->window;
1007 if ( window )
1008 {
1009 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
1010 gdk_window_set_background( window, m_backgroundColour.GetColor() );
1011 gdk_window_clear( window );
1012 }
1013 }
1014
1015 GList *child = m_list->children;
1016 while (child)
1017 {
1018 gtk_widget_set_style( GTK_WIDGET(child->data), m_widgetStyle );
1019
1020 GtkBin *bin = GTK_BIN( child->data );
1021 GtkWidget *label = GTK_WIDGET( bin->child );
1022 gtk_widget_set_style( label, m_widgetStyle );
1023
1024 child = child->next;
1025 }
1026 }
1027
1028 void wxListBox::OnInternalIdle()
1029 {
1030 wxCursor cursor = m_cursor;
1031 if (g_globalCursor.Ok()) cursor = g_globalCursor;
1032
1033 if (GTK_WIDGET(m_list)->window && cursor.Ok())
1034 {
1035 /* I now set the cursor the anew in every OnInternalIdle call
1036 as setting the cursor in a parent window also effects the
1037 windows above so that checking for the current cursor is
1038 not possible. */
1039
1040 gdk_window_set_cursor( GTK_WIDGET(m_list)->window, cursor.GetCursor() );
1041
1042 GList *child = m_list->children;
1043 while (child)
1044 {
1045 GtkBin *bin = GTK_BIN( child->data );
1046 GtkWidget *label = GTK_WIDGET( bin->child );
1047
1048 if (!label->window)
1049 break;
1050 else
1051 gdk_window_set_cursor( label->window, cursor.GetCursor() );
1052
1053 child = child->next;
1054 }
1055 }
1056
1057 UpdateWindowUI();
1058 }
1059
1060 #endif