1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  12 #pragma implementation "listbox.h" 
  15 #include "wx/listbox.h" 
  19 #include "wx/dynarray.h" 
  22 #include "wx/checklst.h" 
  23 #include "wx/settings.h" 
  24 #include "wx/gtk/private.h" 
  27 #include "wx/tooltip.h" 
  32 #include <gdk/gdkkeysyms.h> 
  34 //----------------------------------------------------------------------------- 
  36 //----------------------------------------------------------------------------- 
  38 extern void wxapp_install_idle_handler(); 
  41 //----------------------------------------------------------------------------- 
  43 //----------------------------------------------------------------------------- 
  45 extern bool           g_blockEventsOnDrag
; 
  46 extern bool           g_blockEventsOnScroll
; 
  47 extern wxCursor       g_globalCursor
; 
  48 extern wxWindowGTK   
*g_delayedFocus
; 
  50 static bool       g_hasDoubleClicked 
= FALSE
; 
  52 //----------------------------------------------------------------------------- 
  53 // idle callback for SetFirstItem 
  54 //----------------------------------------------------------------------------- 
  56 struct wxlistbox_idle_struct
 
  63 extern "C" gint 
wxlistbox_idle_callback( gpointer gdata 
) 
  65     wxlistbox_idle_struct
* data 
= (wxlistbox_idle_struct
*) gdata
; 
  68     gtk_idle_remove( data
->m_tag 
); 
  70     // check that the items haven't been deleted from the listbox since we had 
  71     // installed this callback 
  72     wxListBox 
*lbox 
= data
->m_listbox
; 
  73     if ( data
->m_item 
< lbox
->GetCount() ) 
  75         lbox
->SetFirstItem( data
->m_item 
); 
  85 //----------------------------------------------------------------------------- 
  86 // "button_release_event" 
  87 //----------------------------------------------------------------------------- 
  89 /* we would normally emit a wxEVT_COMMAND_LISTBOX_DOUBLECLICKED event once 
  90    a GDK_2BUTTON_PRESS occurs, but this has the particular problem of the 
  91    listbox keeping the focus until it receives a GDK_BUTTON_RELEASE event. 
  92    this can lead to race conditions so that we emit the dclick event 
  93    after the GDK_BUTTON_RELEASE event after the GDK_2BUTTON_PRESS event */ 
  96 gtk_listbox_button_release_callback( GtkWidget 
* WXUNUSED(widget
), 
  97                                      GdkEventButton 
* WXUNUSED(gdk_event
), 
 100     if (g_isIdle
) wxapp_install_idle_handler(); 
 102     if (g_blockEventsOnDrag
) return FALSE
; 
 103     if (g_blockEventsOnScroll
) return FALSE
; 
 105     if (!listbox
->m_hasVMT
) return FALSE
; 
 107     if (!g_hasDoubleClicked
) return FALSE
; 
 109     wxCommandEvent 
event( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
, listbox
->GetId() ); 
 110     event
.SetEventObject( listbox 
); 
 112     wxArrayInt aSelections
; 
 113     int n
, count 
= listbox
->GetSelections(aSelections
); 
 117         if ( listbox
->HasClientObjectData() ) 
 118             event
.SetClientObject( listbox
->GetClientObject(n
) ); 
 119         else if ( listbox
->HasClientUntypedData() ) 
 120             event
.SetClientData( listbox
->GetClientData(n
) ); 
 121         event
.SetString( listbox
->GetString(n
) ); 
 128     event
.m_commandInt 
= n
; 
 130     listbox
->GetEventHandler()->ProcessEvent( event 
); 
 135 //----------------------------------------------------------------------------- 
 136 // "button_press_event" 
 137 //----------------------------------------------------------------------------- 
 140 gtk_listbox_button_press_callback( GtkWidget 
*widget
, 
 141                                    GdkEventButton 
*gdk_event
, 
 144     if (g_isIdle
) wxapp_install_idle_handler(); 
 146     if (g_blockEventsOnDrag
) return FALSE
; 
 147     if (g_blockEventsOnScroll
) return FALSE
; 
 149     if (!listbox
->m_hasVMT
) return FALSE
; 
 151     int sel 
= listbox
->GtkGetIndex( widget 
); 
 153 #if wxUSE_CHECKLISTBOX 
 154     if ((listbox
->m_hasCheckBoxes
) && (gdk_event
->x 
< 15) && (gdk_event
->type 
!= GDK_2BUTTON_PRESS
)) 
 156         wxCheckListBox 
*clb 
= (wxCheckListBox 
*)listbox
; 
 158         clb
->Check( sel
, !clb
->IsChecked(sel
) ); 
 160         wxCommandEvent 
event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, listbox
->GetId() ); 
 161         event
.SetEventObject( listbox 
); 
 163         listbox
->GetEventHandler()->ProcessEvent( event 
); 
 165 #endif // wxUSE_CHECKLISTBOX 
 167     /* emit wxEVT_COMMAND_LISTBOX_DOUBLECLICKED later */ 
 168     g_hasDoubleClicked 
= (gdk_event
->type 
== GDK_2BUTTON_PRESS
); 
 173 //----------------------------------------------------------------------------- 
 175 //----------------------------------------------------------------------------- 
 178 gtk_listbox_key_press_callback( GtkWidget 
*widget
, GdkEventKey 
*gdk_event
, wxListBox 
*listbox 
) 
 181         wxapp_install_idle_handler(); 
 183     if (g_blockEventsOnDrag
) 
 188     if ((gdk_event
->keyval 
== GDK_Tab
) || (gdk_event
->keyval 
== GDK_ISO_Left_Tab
)) 
 190         wxNavigationKeyEvent new_event
; 
 191         /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */ 
 192         new_event
.SetDirection( (gdk_event
->keyval 
== GDK_Tab
) ); 
 193         /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */ 
 194         new_event
.SetWindowChange( (gdk_event
->state 
& GDK_CONTROL_MASK
) ); 
 195         new_event
.SetCurrentFocus( listbox 
); 
 196         ret 
= listbox
->GetEventHandler()->ProcessEvent( new_event 
); 
 199     if ((gdk_event
->keyval 
== GDK_Return
) && (!ret
)) 
 201         // eat return in all modes 
 205 #if wxUSE_CHECKLISTBOX 
 206     if ((gdk_event
->keyval 
== ' ') && (listbox
->m_hasCheckBoxes
) && (!ret
)) 
 208         int sel 
= listbox
->GtkGetIndex( widget 
); 
 210         wxCheckListBox 
*clb 
= (wxCheckListBox 
*)listbox
; 
 212         clb
->Check( sel
, !clb
->IsChecked(sel
) ); 
 214         wxCommandEvent 
new_event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, listbox
->GetId() ); 
 215         new_event
.SetEventObject( listbox 
); 
 216         new_event
.SetInt( sel 
); 
 217         ret 
= listbox
->GetEventHandler()->ProcessEvent( new_event 
); 
 219 #endif // wxUSE_CHECKLISTBOX 
 223         gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" ); 
 230 //----------------------------------------------------------------------------- 
 231 // "select" and "deselect" 
 232 //----------------------------------------------------------------------------- 
 234 static void gtk_listitem_select_cb( GtkWidget 
*widget
, wxListBox 
*listbox
, bool is_selection 
); 
 236 static void gtk_listitem_select_callback( GtkWidget 
*widget
, wxListBox 
*listbox 
) 
 238     gtk_listitem_select_cb( widget
, listbox
, TRUE 
); 
 241 static void gtk_listitem_deselect_callback( GtkWidget 
*widget
, wxListBox 
*listbox 
) 
 243     gtk_listitem_select_cb( widget
, listbox
, FALSE 
); 
 246 static void gtk_listitem_select_cb( GtkWidget 
*widget
, wxListBox 
*listbox
, bool is_selection 
) 
 248     if (g_isIdle
) wxapp_install_idle_handler(); 
 250     if (!listbox
->m_hasVMT
) return; 
 251     if (g_blockEventsOnDrag
) return; 
 253     if (listbox
->m_blockEvent
) return; 
 255     wxCommandEvent 
event(wxEVT_COMMAND_LISTBOX_SELECTED
, listbox
->GetId() ); 
 256     event
.SetEventObject( listbox 
); 
 258 //    MSW doesn't do that either 
 259 //    event.SetExtraLong( (long) is_selection ); 
 262     if ((listbox
->GetWindowStyleFlag() & wxLB_SINGLE
) != 0) 
 264         int sel 
= listbox
->GtkGetIndex( widget 
); 
 266         if (listbox
->m_prevSelection 
!= sel
) 
 267             gtk_list_unselect_item( listbox
->m_list
, listbox
->m_prevSelection 
); 
 269         listbox
->m_prevSelection 
= sel
; 
 272     wxArrayInt aSelections
; 
 273     int n
, count 
= listbox
->GetSelections(aSelections
); 
 277         if ( listbox
->HasClientObjectData() ) 
 278             event
.SetClientObject( listbox
->GetClientObject(n
) ); 
 279         else if ( listbox
->HasClientUntypedData() ) 
 280             event
.SetClientData( listbox
->GetClientData(n
) ); 
 281         event
.SetString( listbox
->GetString(n
) ); 
 288     event
.m_commandInt 
= n
; 
 290 //    No longer required with new code in wxLB_SINGLE 
 291 //    listbox->GetEventHandler()->AddPendingEvent( event ); 
 292     listbox
->GetEventHandler()->ProcessEvent( event 
); 
 295 //----------------------------------------------------------------------------- 
 297 //----------------------------------------------------------------------------- 
 299 IMPLEMENT_DYNAMIC_CLASS(wxListBox
,wxControl
) 
 301 // ---------------------------------------------------------------------------- 
 303 // ---------------------------------------------------------------------------- 
 305 wxListBox::wxListBox() 
 307     m_list 
= (GtkList 
*) NULL
; 
 308 #if wxUSE_CHECKLISTBOX 
 309     m_hasCheckBoxes 
= FALSE
; 
 310 #endif // wxUSE_CHECKLISTBOX 
 313 bool wxListBox::Create( wxWindow 
*parent
, wxWindowID id
, 
 314                         const wxPoint 
&pos
, const wxSize 
&size
, 
 315                         int n
, const wxString choices
[], 
 316                         long style
, const wxValidator
& validator
, 
 317                         const wxString 
&name 
) 
 320     m_acceptsFocus 
= TRUE
; 
 321     m_prevSelection 
= 0;  // or -1 ?? 
 322     m_blockEvent 
= FALSE
; 
 324     if (!PreCreation( parent
, pos
, size 
) || 
 325         !CreateBase( parent
, id
, pos
, size
, style
, validator
, name 
)) 
 327         wxFAIL_MSG( wxT("wxListBox creation failed") ); 
 331     m_widget 
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL 
); 
 332     if (style 
& wxLB_ALWAYS_SB
) 
 334       gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget
), 
 335         GTK_POLICY_AUTOMATIC
, GTK_POLICY_ALWAYS 
); 
 339       gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget
), 
 340         GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC 
); 
 343     m_list 
= GTK_LIST( gtk_list_new() ); 
 345     GtkSelectionMode mode
; 
 346     if (style 
& wxLB_MULTIPLE
) 
 348         mode 
= GTK_SELECTION_MULTIPLE
; 
 350     else if (style 
& wxLB_EXTENDED
) 
 352         mode 
= GTK_SELECTION_EXTENDED
; 
 356         // if style was 0 set single mode 
 357         m_windowStyle 
|= wxLB_SINGLE
; 
 358         mode 
= GTK_SELECTION_MULTIPLE
; 
 361     gtk_list_set_selection_mode( GTK_LIST(m_list
), mode 
); 
 363     gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(m_widget
), GTK_WIDGET(m_list
) ); 
 365     /* make list scroll when moving the focus down using cursor keys */ 
 366     gtk_container_set_focus_vadjustment( 
 367         GTK_CONTAINER(m_list
), 
 368         gtk_scrolled_window_get_vadjustment( 
 369             GTK_SCROLLED_WINDOW(m_widget
))); 
 371     gtk_widget_show( GTK_WIDGET(m_list
) ); 
 373     if ( style 
& wxLB_SORT 
) 
 375         // this will change DoAppend() behaviour 
 376         m_strings 
= new wxSortedArrayString
; 
 380         m_strings 
= (wxSortedArrayString 
*)NULL
; 
 383     for (int i 
= 0; i 
< n
; i
++) 
 386         DoAppend(choices
[i
]); 
 389     // call it after appending the strings to the listbox, otherwise it doesn't 
 393     m_parent
->DoAddChild( this ); 
 397     SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX 
) ); 
 398     SetForegroundColour( parent
->GetForegroundColour() ); 
 399     SetFont( parent
->GetFont() ); 
 406 wxListBox::~wxListBox() 
 416 // ---------------------------------------------------------------------------- 
 418 // ---------------------------------------------------------------------------- 
 420 void wxListBox::DoInsertItems(const wxArrayString
& items
, int pos
) 
 422     wxCHECK_RET( m_list 
!= NULL
, wxT("invalid listbox") ); 
 424     // VZ: notice that InsertItems knows nothing about sorting, so calling it 
 425     //     from outside (and not from our own Append) is likely to break 
 428     // code elsewhere supposes we have as many items in m_clientList as items 
 430     wxASSERT_MSG( m_clientList
.GetCount() == (size_t)GetCount(), 
 431                   wxT("bug in client data management") ); 
 433     GList 
*children 
= m_list
->children
; 
 434     int length 
= g_list_length(children
); 
 436     wxCHECK_RET( pos 
<= length
, wxT("invalid index in wxListBox::InsertItems") ); 
 438     size_t nItems 
= items
.GetCount(); 
 443         for (size_t n 
= 0; n 
< nItems
; n
++) 
 445             index 
= m_strings
->Add( items
[n
] ); 
 447             if (index 
!= GetCount()) 
 449                 GtkAddItem( items
[n
], index 
); 
 450                 wxNode 
*node 
= m_clientList
.Item( index 
); 
 451                 m_clientList
.Insert( node
, (wxObject
*) NULL 
); 
 455                 GtkAddItem( items
[n
] ); 
 456                 m_clientList
.Append( (wxObject
*) NULL 
); 
 464             for ( size_t n 
= 0; n 
< nItems
; n
++ ) 
 466                 GtkAddItem( items
[n
] ); 
 468                 m_clientList
.Append((wxObject 
*)NULL
); 
 473             wxNode 
*node 
= m_clientList
.Item( pos 
); 
 474             for ( size_t n 
= 0; n 
< nItems
; n
++ ) 
 476                 GtkAddItem( items
[n
], pos
+n 
); 
 478                 m_clientList
.Insert( node
, (wxObject 
*)NULL 
); 
 483     wxASSERT_MSG( m_clientList
.GetCount() == (size_t)GetCount(), 
 484                       wxT("bug in client data management") ); 
 487 int wxListBox::DoAppend( const wxString
& item 
) 
 491         // need to determine the index 
 492         int index 
= m_strings
->Add( item 
); 
 494         // only if not at the end anyway 
 495         if (index 
!= GetCount()) 
 497            GtkAddItem( item
, index 
); 
 499            wxNode 
*node 
= m_clientList
.Item( index 
); 
 500            m_clientList
.Insert( node
, (wxObject 
*)NULL 
); 
 508     m_clientList
.Append((wxObject 
*)NULL
); 
 510     return GetCount() - 1; 
 513 void wxListBox::GtkAddItem( const wxString 
&item
, int pos 
) 
 515     wxCHECK_RET( m_list 
!= NULL
, wxT("invalid listbox") ); 
 517     GtkWidget 
*list_item
; 
 519     wxString 
label(item
); 
 520 #if wxUSE_CHECKLISTBOX 
 523         label
.Prepend(wxCHECKLBOX_STRING
); 
 525 #endif // wxUSE_CHECKLISTBOX 
 527     list_item 
= gtk_list_item_new_with_label( wxGTK_CONV( label 
) ); 
 529     GList 
*gitem_list 
= g_list_alloc (); 
 530     gitem_list
->data 
= list_item
; 
 533         gtk_list_append_items( GTK_LIST (m_list
), gitem_list 
); 
 535         gtk_list_insert_items( GTK_LIST (m_list
), gitem_list
, pos 
); 
 537     gtk_signal_connect( GTK_OBJECT(list_item
), "select", 
 538       GTK_SIGNAL_FUNC(gtk_listitem_select_callback
), (gpointer
)this ); 
 540     if (HasFlag(wxLB_MULTIPLE
) || HasFlag(wxLB_EXTENDED
)) 
 541         gtk_signal_connect( GTK_OBJECT(list_item
), "deselect", 
 542           GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback
), (gpointer
)this ); 
 544     gtk_signal_connect( GTK_OBJECT(list_item
), 
 545                         "button_press_event", 
 546                         (GtkSignalFunc
)gtk_listbox_button_press_callback
, 
 549     gtk_signal_connect_after( GTK_OBJECT(list_item
), 
 550                         "button_release_event", 
 551                         (GtkSignalFunc
)gtk_listbox_button_release_callback
, 
 554     gtk_signal_connect( GTK_OBJECT(list_item
), 
 556                            (GtkSignalFunc
)gtk_listbox_key_press_callback
, 
 559     ConnectWidget( list_item 
); 
 561     gtk_widget_show( list_item 
); 
 563     if (GTK_WIDGET_REALIZED(m_widget
)) 
 565         gtk_widget_realize( list_item 
); 
 566         gtk_widget_realize( GTK_BIN(list_item
)->child 
); 
 568         // Apply current widget style to the new list_item 
 571             gtk_widget_set_style( GTK_WIDGET( list_item 
), m_widgetStyle 
); 
 572             GtkBin 
*bin 
= GTK_BIN( list_item 
); 
 573             GtkWidget 
*label 
= GTK_WIDGET( bin
->child 
); 
 574             gtk_widget_set_style( label
, m_widgetStyle 
); 
 578         if (m_tooltip
) m_tooltip
->Apply( this ); 
 583 void wxListBox::DoSetItems( const wxArrayString
& items
, 
 588     DoInsertItems(items
, 0); 
 592         size_t count 
= items
.GetCount(); 
 593         for ( size_t n 
= 0; n 
< count
; n
++ ) 
 595             SetClientData(n
, clientData
[n
]); 
 600 // ---------------------------------------------------------------------------- 
 602 // ---------------------------------------------------------------------------- 
 604 void wxListBox::Clear() 
 606     wxCHECK_RET( m_list 
!= NULL
, wxT("invalid listbox") ); 
 608     gtk_list_clear_items( m_list
, 0, GetCount() ); 
 610     if ( GTK_LIST(m_list
)->last_focus_child 
!= NULL  
) 
 612         // This should be NULL, I think. 
 613         GTK_LIST(m_list
)->last_focus_child 
= NULL
; 
 616     if ( HasClientObjectData() ) 
 618         // destroy the data (due to Robert's idea of using wxList<wxObject> 
 619         // and not wxList<wxClientData> we can't just say 
 620         // m_clientList.DeleteContents(TRUE) - this would crash! 
 621         wxNode 
*node 
= m_clientList
.GetFirst(); 
 624             delete (wxClientData 
*)node
->GetData(); 
 625             node 
= node
->GetNext(); 
 628     m_clientList
.Clear(); 
 634 void wxListBox::Delete( int n 
) 
 636     wxCHECK_RET( m_list 
!= NULL
, wxT("invalid listbox") ); 
 638     GList 
*child 
= g_list_nth( m_list
->children
, n 
); 
 640     wxCHECK_RET( child
, wxT("wrong listbox index") ); 
 642     GList 
*list 
= g_list_append( (GList
*) NULL
, child
->data 
); 
 643     gtk_list_remove_items( m_list
, list 
); 
 646     wxNode 
*node 
= m_clientList
.Item( n 
); 
 649         if ( m_clientDataItemsType 
== wxClientData_Object 
) 
 651             wxClientData 
*cd 
= (wxClientData
*)node
->GetData(); 
 655         m_clientList
.DeleteNode( node 
); 
 659         m_strings
->Remove(n
); 
 662 // ---------------------------------------------------------------------------- 
 664 // ---------------------------------------------------------------------------- 
 666 void wxListBox::DoSetItemClientData( int n
, void* clientData 
) 
 668     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid listbox control") ); 
 670     wxNode 
*node 
= m_clientList
.Item( n 
); 
 671     wxCHECK_RET( node
, wxT("invalid index in wxListBox::DoSetItemClientData") ); 
 673     node
->SetData( (wxObject
*) clientData 
); 
 676 void* wxListBox::DoGetItemClientData( int n 
) const 
 678     wxCHECK_MSG( m_widget 
!= NULL
, NULL
, wxT("invalid listbox control") ); 
 680     wxNode 
*node 
= m_clientList
.Item( n 
); 
 681     wxCHECK_MSG( node
, NULL
, wxT("invalid index in wxListBox::DoGetItemClientData") ); 
 683     return node
->GetData(); 
 686 void wxListBox::DoSetItemClientObject( int n
, wxClientData
* clientData 
) 
 688     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid listbox control") ); 
 690     wxNode 
*node 
= m_clientList
.Item( n 
); 
 691     wxCHECK_RET( node
, wxT("invalid index in wxListBox::DoSetItemClientObject") ); 
 693     // wxItemContainer already deletes data for us 
 695     node
->SetData( (wxObject
*) clientData 
); 
 698 wxClientData
* wxListBox::DoGetItemClientObject( int n 
) const 
 700     wxCHECK_MSG( m_widget 
!= NULL
, (wxClientData
*) NULL
, wxT("invalid listbox control") ); 
 702     wxNode 
*node 
= m_clientList
.Item( n 
); 
 703     wxCHECK_MSG( node
, (wxClientData 
*)NULL
, 
 704                  wxT("invalid index in wxListBox::DoGetItemClientObject") ); 
 706     return (wxClientData
*) node
->GetData(); 
 709 // ---------------------------------------------------------------------------- 
 710 // string list access 
 711 // ---------------------------------------------------------------------------- 
 713 wxString 
wxListBox::GetRealLabel(GList 
*item
) const 
 715     GtkBin 
*bin 
= GTK_BIN( item
->data 
); 
 716     GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 721     str 
= wxGTK_CONV_BACK( gtk_label_get_text( label 
) ); 
 723     str 
= wxString( label
->label 
); 
 726 #if wxUSE_CHECKLISTBOX 
 727     // checklistboxes have "[±] " prepended to their lables, remove it 
 729     // NB: 4 below is the length of wxCHECKLBOX_STRING from wx/gtk/checklst.h 
 730     if ( m_hasCheckBoxes 
) 
 732 #endif // wxUSE_CHECKLISTBOX 
 737 void wxListBox::SetString( int n
, const wxString 
&string 
) 
 739     wxCHECK_RET( m_list 
!= NULL
, wxT("invalid listbox") ); 
 741     GList 
*child 
= g_list_nth( m_list
->children
, n 
); 
 744         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 745         GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 748 #if wxUSE_CHECKLISTBOX 
 750             str 
+= wxCHECKLBOX_STRING
; 
 751 #endif // wxUSE_CHECKLISTBOX 
 754         gtk_label_set( label
, wxGTK_CONV( str 
) ); 
 758         wxFAIL_MSG(wxT("wrong listbox index")); 
 762 wxString 
wxListBox::GetString( int n 
) const 
 764     wxCHECK_MSG( m_list 
!= NULL
, wxT(""), wxT("invalid listbox") ); 
 766     GList 
*child 
= g_list_nth( m_list
->children
, n 
); 
 769         return GetRealLabel(child
); 
 772     wxFAIL_MSG(wxT("wrong listbox index")); 
 777 int wxListBox::GetCount() const 
 779     wxCHECK_MSG( m_list 
!= NULL
, -1, wxT("invalid listbox") ); 
 781     GList 
*children 
= m_list
->children
; 
 782     return g_list_length(children
); 
 785 int wxListBox::FindString( const wxString 
&item 
) const 
 787     wxCHECK_MSG( m_list 
!= NULL
, -1, wxT("invalid listbox") ); 
 789     GList 
*child 
= m_list
->children
; 
 793         if ( GetRealLabel(child
) == item 
) 
 800     // it's not an error if the string is not found -> no wxCHECK 
 805 // ---------------------------------------------------------------------------- 
 807 // ---------------------------------------------------------------------------- 
 809 int wxListBox::GetSelection() const 
 811     wxCHECK_MSG( m_list 
!= NULL
, -1, wxT("invalid listbox") ); 
 813     GList 
*child 
= m_list
->children
; 
 817         if (GTK_WIDGET(child
->data
)->state 
== GTK_STATE_SELECTED
) return count
; 
 824 int wxListBox::GetSelections( wxArrayInt
& aSelections 
) const 
 826     wxCHECK_MSG( m_list 
!= NULL
, -1, wxT("invalid listbox") ); 
 828     // get the number of selected items first 
 829     GList 
*child 
= m_list
->children
; 
 831     for (child 
= m_list
->children
; child 
!= NULL
; child 
= child
->next
) 
 833         if (GTK_WIDGET(child
->data
)->state 
== GTK_STATE_SELECTED
) 
 842         aSelections
.Alloc(count
); // optimization attempt 
 844         for (child 
= m_list
->children
; child 
!= NULL
; child 
= child
->next
, i
++) 
 846             if (GTK_WIDGET(child
->data
)->state 
== GTK_STATE_SELECTED
) 
 854 bool wxListBox::IsSelected( int n 
) const 
 856     wxCHECK_MSG( m_list 
!= NULL
, FALSE
, wxT("invalid listbox") ); 
 858     GList 
*target 
= g_list_nth( m_list
->children
, n 
); 
 860     wxCHECK_MSG( target
, FALSE
, wxT("invalid listbox index") ); 
 862     return (GTK_WIDGET(target
->data
)->state 
== GTK_STATE_SELECTED
) ; 
 865 void wxListBox::SetSelection( int n
, bool select 
) 
 867     wxCHECK_RET( m_list 
!= NULL
, wxT("invalid listbox") ); 
 873         if ((m_windowStyle 
& wxLB_SINGLE
) != 0) 
 874             gtk_list_unselect_item( m_list
, m_prevSelection 
); 
 875         gtk_list_select_item( m_list
, n 
); 
 879         gtk_list_unselect_item( m_list
, n 
); 
 881     m_blockEvent 
= FALSE
; 
 884 void wxListBox::DoSetFirstItem( int n 
) 
 886     wxCHECK_RET( m_list
, wxT("invalid listbox") ); 
 888     if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (m_list
)) 
 891     // terribly efficient 
 892     const gchar 
*vadjustment_key 
= "gtk-vadjustment"; 
 893     guint vadjustment_key_id 
= g_quark_from_static_string (vadjustment_key
); 
 895     GtkAdjustment 
*adjustment 
= 
 896        (GtkAdjustment
*) gtk_object_get_data_by_id (GTK_OBJECT (m_list
), vadjustment_key_id
); 
 897     wxCHECK_RET( adjustment
, wxT("invalid listbox code") ); 
 899     GList 
*target 
= g_list_nth( m_list
->children
, n 
); 
 900     wxCHECK_RET( target
, wxT("invalid listbox index") ); 
 902     GtkWidget 
*item 
= GTK_WIDGET(target
->data
); 
 903     wxCHECK_RET( item
, wxT("invalid listbox code") ); 
 905     if (item
->allocation
.y 
== -1) 
 907         wxlistbox_idle_struct
* data 
= new wxlistbox_idle_struct
; 
 908         data
->m_listbox 
= this; 
 910         data
->m_tag 
= gtk_idle_add_priority( 800, wxlistbox_idle_callback
, (gpointer
) data 
); 
 915     float y 
= item
->allocation
.y
; 
 916     if (y 
> adjustment
->upper 
- adjustment
->page_size
) 
 917         y 
= adjustment
->upper 
- adjustment
->page_size
; 
 918     gtk_adjustment_set_value( adjustment
, y 
); 
 921 // ---------------------------------------------------------------------------- 
 923 // ---------------------------------------------------------------------------- 
 925 int wxListBox::GtkGetIndex( GtkWidget 
*item 
) const 
 929         GList 
*child 
= m_list
->children
; 
 933             if (GTK_WIDGET(child
->data
) == item
) return count
; 
 942 void wxListBox::ApplyToolTip( GtkTooltips 
*tips
, const wxChar 
*tip 
) 
 944     GList 
*child 
= m_list
->children
; 
 947         gtk_tooltips_set_tip( tips
, GTK_WIDGET( child
->data 
), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL 
); 
 951 #endif // wxUSE_TOOLTIPS 
 953 GtkWidget 
*wxListBox::GetConnectWidget() 
 955     return GTK_WIDGET(m_list
); 
 958 bool wxListBox::IsOwnGtkWindow( GdkWindow 
*window 
) 
 960     if (GTK_WIDGET(m_list
)->window 
== window
) return TRUE
; 
 962     GList 
*child 
= m_list
->children
; 
 965         GtkWidget 
*bin 
= GTK_WIDGET( child
->data 
); 
 966         if (bin
->window 
== window
) return TRUE
; 
 973 void wxListBox::ApplyWidgetStyle() 
 977     if (m_backgroundColour
.Ok()) 
 979         GdkWindow 
*window 
= GTK_WIDGET(m_list
)->window
; 
 982             m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window 
) ); 
 983             gdk_window_set_background( window
, m_backgroundColour
.GetColor() ); 
 984             gdk_window_clear( window 
); 
 988     GList 
*child 
= m_list
->children
; 
 991         gtk_widget_set_style( GTK_WIDGET(child
->data
), m_widgetStyle 
); 
 993         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 994         GtkWidget 
*label 
= GTK_WIDGET( bin
->child 
); 
 995         gtk_widget_set_style( label
, m_widgetStyle 
); 
1001 void wxListBox::OnInternalIdle() 
1003     wxCursor cursor 
= m_cursor
; 
1004     if (g_globalCursor
.Ok()) cursor 
= g_globalCursor
; 
1006     if (GTK_WIDGET(m_list
)->window 
&& cursor
.Ok()) 
1008         /* I now set the cursor the anew in every OnInternalIdle call 
1009            as setting the cursor in a parent window also effects the 
1010            windows above so that checking for the current cursor is 
1013         gdk_window_set_cursor( GTK_WIDGET(m_list
)->window
, cursor
.GetCursor() ); 
1015         GList 
*child 
= m_list
->children
; 
1018             GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
1019             GtkWidget 
*label 
= GTK_WIDGET( bin
->child 
); 
1024                 gdk_window_set_cursor( label
->window
, cursor
.GetCursor() ); 
1026             child 
= child
->next
; 
1030     if (g_delayedFocus 
== this) 
1032         if (GTK_WIDGET_REALIZED(m_widget
)) 
1034             gtk_widget_grab_focus( m_widget 
); 
1035             g_delayedFocus 
= NULL
; 
1042 wxSize 
wxListBox::DoGetBestSize() const 
1044     int lbWidth 
= 100;  // some defaults 
1048     // Find the widest line 
1049     for(int i 
= 0; i 
< GetCount(); i
++) { 
1050         wxString 
str(GetString(i
)); 
1051         GetTextExtent(str
, &wLine
, NULL
); 
1052         lbWidth 
= wxMax(lbWidth
, wLine
); 
1055     // Add room for the scrollbar 
1056     lbWidth 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
1058     // And just a bit more 
1060     GetTextExtent( wxT("X"), &cx
, &cy
); 
1063     // don't make the listbox too tall (limit height to around 10 items) but don't 
1064     // make it too small neither 
1065     lbHeight 
= (cy
+4) * wxMin(wxMax(GetCount(), 3), 10); 
1067     return wxSize(lbWidth
, lbHeight
); 
1070 void wxListBox::FixUpMouseEvent(GtkWidget 
*widget
, wxCoord
& x
, wxCoord
& y
) 
1072     // the mouse event coords are relative to the listbox items, we need to 
1073     // translate them to the normal client coords 
1074     x 
+= widget
->allocation
.x
; 
1075     y 
+= widget
->allocation
.y
; 
1078 #endif // wxUSE_LISTBOX