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" 
  26 #include "wx/tooltip.h" 
  31 #include <gdk/gdkkeysyms.h> 
  33 //----------------------------------------------------------------------------- 
  35 //----------------------------------------------------------------------------- 
  37 extern void wxapp_install_idle_handler(); 
  40 //----------------------------------------------------------------------------- 
  42 //----------------------------------------------------------------------------- 
  44 #if wxUSE_CHECKLISTBOX 
  46 // checklistboxes have "[±] " prepended to their lables, this macro removes it 
  47 // (NB: 4 below is the length of wxCHECKLBOX_STRING above) 
  49 // the argument to it is a "const char *" pointer 
  50 #define GET_REAL_LABEL(label) ((m_hasCheckBoxes)?(label)+4 : (label)) 
  52 #else // !wxUSE_CHECKLISTBOX 
  54 #define GET_REAL_LABEL(label) (label) 
  56 #endif // wxUSE_CHECKLISTBOX 
  58 //----------------------------------------------------------------------------- 
  60 //----------------------------------------------------------------------------- 
  62 extern bool       g_blockEventsOnDrag
; 
  63 extern bool       g_blockEventsOnScroll
; 
  64 extern wxCursor   g_globalCursor
; 
  66 static bool       g_hasDoubleClicked 
= FALSE
; 
  68 //----------------------------------------------------------------------------- 
  69 // idle callback for SetFirstItem 
  70 //----------------------------------------------------------------------------- 
  72 struct wxlistbox_idle_struct
 
  79 extern "C" gint 
wxlistbox_idle_callback( gpointer gdata 
) 
  81     wxlistbox_idle_struct
* data 
= (wxlistbox_idle_struct
*) gdata
; 
  84     gtk_idle_remove( data
->m_tag 
); 
  86     data
->m_listbox
->SetFirstItem( data
->m_item 
); 
  95 //----------------------------------------------------------------------------- 
  96 // "button_release_event" 
  97 //----------------------------------------------------------------------------- 
  99 /* we would normally emit a wxEVT_COMMAND_LISTBOX_DOUBLECLICKED event once 
 100    a GDK_2BUTTON_PRESS occurs, but this has the particular problem of the 
 101    listbox keeping the focus until it receives a GDK_BUTTON_RELEASE event. 
 102    this can lead to race conditions so that we emit the dclick event 
 103    after the GDK_BUTTON_RELEASE event after the GDK_2BUTTON_PRESS event */ 
 106 gtk_listbox_button_release_callback( GtkWidget 
* WXUNUSED(widget
), 
 107                                      GdkEventButton 
* WXUNUSED(gdk_event
), 
 110     if (g_isIdle
) wxapp_install_idle_handler(); 
 112     if (g_blockEventsOnDrag
) return FALSE
; 
 113     if (g_blockEventsOnScroll
) return FALSE
; 
 115     if (!listbox
->m_hasVMT
) return FALSE
; 
 117     if (!g_hasDoubleClicked
) return FALSE
; 
 119     wxCommandEvent 
event( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
, listbox
->GetId() ); 
 120     event
.SetEventObject( listbox 
); 
 122     wxArrayInt aSelections
; 
 123     int n
, count 
= listbox
->GetSelections(aSelections
); 
 127         if ( listbox
->HasClientObjectData() ) 
 128             event
.SetClientObject( listbox
->GetClientObject(n
) ); 
 129         else if ( listbox
->HasClientUntypedData() ) 
 130             event
.SetClientData( listbox
->GetClientData(n
) ); 
 131         event
.SetString( listbox
->GetString(n
) ); 
 138     event
.m_commandInt 
= n
; 
 140     listbox
->GetEventHandler()->ProcessEvent( event 
); 
 145 //----------------------------------------------------------------------------- 
 146 // "button_press_event" 
 147 //----------------------------------------------------------------------------- 
 150 gtk_listbox_button_press_callback( GtkWidget 
*widget
, 
 151                                    GdkEventButton 
*gdk_event
, 
 154     if (g_isIdle
) wxapp_install_idle_handler(); 
 156     if (g_blockEventsOnDrag
) return FALSE
; 
 157     if (g_blockEventsOnScroll
) return FALSE
; 
 159     if (!listbox
->m_hasVMT
) return FALSE
; 
 161     int sel 
= listbox
->GtkGetIndex( widget 
); 
 163 #if wxUSE_CHECKLISTBOX 
 164     if ((listbox
->m_hasCheckBoxes
) && (gdk_event
->x 
< 15) && (gdk_event
->type 
!= GDK_2BUTTON_PRESS
)) 
 166         wxCheckListBox 
*clb 
= (wxCheckListBox 
*)listbox
; 
 168         clb
->Check( sel
, !clb
->IsChecked(sel
) ); 
 170         wxCommandEvent 
event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, listbox
->GetId() ); 
 171         event
.SetEventObject( listbox 
); 
 173         listbox
->GetEventHandler()->ProcessEvent( event 
); 
 175 #endif // wxUSE_CHECKLISTBOX 
 177     /* emit wxEVT_COMMAND_LISTBOX_DOUBLECLICKED later */ 
 178     g_hasDoubleClicked 
= (gdk_event
->type 
== GDK_2BUTTON_PRESS
); 
 183 //----------------------------------------------------------------------------- 
 185 //----------------------------------------------------------------------------- 
 188 gtk_listbox_key_press_callback( GtkWidget 
*widget
, GdkEventKey 
*gdk_event
, wxListBox 
*listbox 
) 
 191         wxapp_install_idle_handler(); 
 193     if (g_blockEventsOnDrag
) 
 198     if ((gdk_event
->keyval 
== GDK_Tab
) || (gdk_event
->keyval 
== GDK_ISO_Left_Tab
)) 
 200         wxNavigationKeyEvent new_event
; 
 201         /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */ 
 202         new_event
.SetDirection( (gdk_event
->keyval 
== GDK_Tab
) ); 
 203         /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */ 
 204         new_event
.SetWindowChange( (gdk_event
->state 
& GDK_CONTROL_MASK
) ); 
 205         new_event
.SetCurrentFocus( listbox 
); 
 206         ret 
= listbox
->GetEventHandler()->ProcessEvent( new_event 
); 
 209     if ((gdk_event
->keyval 
== GDK_Return
) && (!ret
)) 
 211         // eat return in all modes 
 215 #if wxUSE_CHECKLISTBOX 
 216     if ((gdk_event
->keyval 
== ' ') && (listbox
->m_hasCheckBoxes
) && (!ret
)) 
 218         int sel 
= listbox
->GtkGetIndex( widget 
); 
 220         wxCheckListBox 
*clb 
= (wxCheckListBox 
*)listbox
; 
 222         clb
->Check( sel
, !clb
->IsChecked(sel
) ); 
 224         wxCommandEvent 
new_event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED
, listbox
->GetId() ); 
 225         new_event
.SetEventObject( listbox 
); 
 226         new_event
.SetInt( sel 
); 
 227         ret 
= listbox
->GetEventHandler()->ProcessEvent( new_event 
); 
 229 #endif // wxUSE_CHECKLISTBOX 
 233         gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" ); 
 240 //----------------------------------------------------------------------------- 
 241 // "select" and "deselect" 
 242 //----------------------------------------------------------------------------- 
 244 static void gtk_listitem_select_cb( GtkWidget 
*widget
, wxListBox 
*listbox
, bool is_selection 
); 
 246 static void gtk_listitem_select_callback( GtkWidget 
*widget
, wxListBox 
*listbox 
) 
 248     gtk_listitem_select_cb( widget
, listbox
, TRUE 
); 
 251 static void gtk_listitem_deselect_callback( GtkWidget 
*widget
, wxListBox 
*listbox 
) 
 253     gtk_listitem_select_cb( widget
, listbox
, FALSE 
); 
 256 static void gtk_listitem_select_cb( GtkWidget 
*widget
, wxListBox 
*listbox
, bool is_selection 
) 
 258     if (g_isIdle
) wxapp_install_idle_handler(); 
 260     if (!listbox
->m_hasVMT
) return; 
 261     if (g_blockEventsOnDrag
) return; 
 263     if (listbox
->m_blockEvent
) return; 
 265     wxCommandEvent 
event(wxEVT_COMMAND_LISTBOX_SELECTED
, listbox
->GetId() ); 
 266     event
.SetEventObject( listbox 
); 
 268 //    MSW doesn't do that either 
 269 //    event.SetExtraLong( (long) is_selection ); 
 272     if ((listbox
->GetWindowStyleFlag() & wxLB_SINGLE
) != 0) 
 274         int sel 
= listbox
->GtkGetIndex( widget 
); 
 276         if (listbox
->m_prevSelection 
!= sel
) 
 277             gtk_list_unselect_item( listbox
->m_list
, listbox
->m_prevSelection 
); 
 279         listbox
->m_prevSelection 
= sel
; 
 282     wxArrayInt aSelections
; 
 283     int n
, count 
= listbox
->GetSelections(aSelections
); 
 287         if ( listbox
->HasClientObjectData() ) 
 288             event
.SetClientObject( listbox
->GetClientObject(n
) ); 
 289         else if ( listbox
->HasClientUntypedData() ) 
 290             event
.SetClientData( listbox
->GetClientData(n
) ); 
 291         event
.SetString( listbox
->GetString(n
) ); 
 298     event
.m_commandInt 
= n
; 
 300 //    No longer required with new code in wxLB_SINGLE 
 301 //    listbox->GetEventHandler()->AddPendingEvent( event ); 
 302     listbox
->GetEventHandler()->ProcessEvent( event 
); 
 305 //----------------------------------------------------------------------------- 
 307 //----------------------------------------------------------------------------- 
 309 IMPLEMENT_DYNAMIC_CLASS(wxListBox
,wxControl
) 
 311 // ---------------------------------------------------------------------------- 
 313 // ---------------------------------------------------------------------------- 
 315 wxListBox::wxListBox() 
 317     m_list 
= (GtkList 
*) NULL
; 
 318 #if wxUSE_CHECKLISTBOX 
 319     m_hasCheckBoxes 
= FALSE
; 
 320 #endif // wxUSE_CHECKLISTBOX 
 323 bool wxListBox::Create( wxWindow 
*parent
, wxWindowID id
, 
 324                         const wxPoint 
&pos
, const wxSize 
&size
, 
 325                         int n
, const wxString choices
[], 
 326                         long style
, const wxValidator
& validator
, 
 327                         const wxString 
&name 
) 
 330     m_acceptsFocus 
= TRUE
; 
 332     m_prevSelection 
= 0;  // or -1 ?? 
 333     m_blockEvent 
= FALSE
; 
 335     if (!PreCreation( parent
, pos
, size 
) || 
 336         !CreateBase( parent
, id
, pos
, size
, style
, validator
, name 
)) 
 338         wxFAIL_MSG( wxT("wxListBox creation failed") ); 
 342     m_widget 
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL 
); 
 343     if (style 
& wxLB_ALWAYS_SB
) 
 345       gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget
), 
 346         GTK_POLICY_AUTOMATIC
, GTK_POLICY_ALWAYS 
); 
 350       gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget
), 
 351         GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC 
); 
 354     m_list 
= GTK_LIST( gtk_list_new() ); 
 356     GtkSelectionMode mode
; 
 357     if (style 
& wxLB_MULTIPLE
) 
 359         mode 
= GTK_SELECTION_MULTIPLE
; 
 361     else if (style 
& wxLB_EXTENDED
) 
 363         mode 
= GTK_SELECTION_EXTENDED
; 
 367         // if style was 0 set single mode 
 368         m_windowStyle 
|= wxLB_SINGLE
; 
 369         mode 
= GTK_SELECTION_MULTIPLE
; 
 372     gtk_list_set_selection_mode( GTK_LIST(m_list
), mode 
); 
 374     gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(m_widget
), GTK_WIDGET(m_list
) ); 
 376     /* make list scroll when moving the focus down using cursor keys */ 
 377     gtk_container_set_focus_vadjustment( 
 378         GTK_CONTAINER(m_list
), 
 379         gtk_scrolled_window_get_vadjustment( 
 380             GTK_SCROLLED_WINDOW(m_widget
))); 
 382     gtk_widget_show( GTK_WIDGET(m_list
) ); 
 384     if ( style 
& wxLB_SORT 
) 
 386         // this will change DoAppend() behaviour 
 387         m_strings 
= new wxSortedArrayString
; 
 391         m_strings 
= (wxSortedArrayString 
*)NULL
; 
 394     for (int i 
= 0; i 
< n
; i
++) 
 397         DoAppend(choices
[i
]); 
 400     // call it after appending the strings to the listbox, otherwise it doesn't 
 404     m_parent
->DoAddChild( this ); 
 408     SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX 
) ); 
 409     SetForegroundColour( parent
->GetForegroundColour() ); 
 410     SetFont( parent
->GetFont() ); 
 417 wxListBox::~wxListBox() 
 427 void wxListBox::DoInsertItems(const wxArrayString
& items
, int pos
) 
 429     wxCHECK_RET( m_list 
!= NULL
, wxT("invalid listbox") ); 
 431     // VZ: notice that InsertItems knows nothing about sorting, so calling it 
 432     //     from outside (and not from our own Append) is likely to break 
 435     // code elsewhere supposes we have as many items in m_clientList as items 
 437     wxASSERT_MSG( m_clientList
.GetCount() == (size_t)GetCount(), 
 438                   wxT("bug in client data management") ); 
 440     GList 
*children 
= m_list
->children
; 
 441     int length 
= g_list_length(children
); 
 443     wxCHECK_RET( pos 
<= length
, wxT("invalid index in wxListBox::InsertItems") ); 
 445     size_t nItems 
= items
.GetCount(); 
 450         for (size_t n 
= 0; n 
< nItems
; n
++) 
 452             index 
= m_strings
->Add( items
[n
] ); 
 454             if (index 
!= GetCount()) 
 456                 GtkAddItem( items
[n
], index 
); 
 457                 wxNode 
*node 
= m_clientList
.Nth( index 
); 
 458                 m_clientList
.Insert( node
, (wxObject
*) NULL 
); 
 462                 GtkAddItem( items
[n
] ); 
 463                 m_clientList
.Append( (wxObject
*) NULL 
); 
 471             for ( size_t n 
= 0; n 
< nItems
; n
++ ) 
 473                 GtkAddItem( items
[n
] ); 
 475                 m_clientList
.Append((wxObject 
*)NULL
); 
 480             wxNode 
*node 
= m_clientList
.Nth( pos 
); 
 481             for ( size_t n 
= 0; n 
< nItems
; n
++ ) 
 483                 GtkAddItem( items
[n
], pos
+n 
); 
 485                 m_clientList
.Insert( node
, (wxObject 
*)NULL 
); 
 490     wxASSERT_MSG( m_clientList
.GetCount() == (size_t)GetCount(), 
 491                       wxT("bug in client data management") ); 
 494 int wxListBox::DoAppend( const wxString
& item 
) 
 498         // need to determine the index 
 499         int index 
= m_strings
->Add( item 
); 
 501         // only if not at the end anyway 
 502         if (index 
!= GetCount()) 
 504            GtkAddItem( item
, index 
); 
 506            wxNode 
*node 
= m_clientList
.Nth( index 
); 
 507            m_clientList
.Insert( node
, (wxObject 
*)NULL 
); 
 515     m_clientList
.Append((wxObject 
*)NULL
); 
 517     return GetCount() - 1; 
 520 void wxListBox::GtkAddItem( const wxString 
&item
, int pos 
) 
 522     wxCHECK_RET( m_list 
!= NULL
, wxT("invalid listbox") ); 
 524     GtkWidget 
*list_item
; 
 526     wxString 
label(item
); 
 527 #if wxUSE_CHECKLISTBOX 
 530         label
.Prepend(wxCHECKLBOX_STRING
); 
 532 #endif // wxUSE_CHECKLISTBOX 
 534     list_item 
= gtk_list_item_new_with_label( label
.mbc_str() ); 
 536     GList 
*gitem_list 
= g_list_alloc (); 
 537     gitem_list
->data 
= list_item
; 
 540         gtk_list_append_items( GTK_LIST (m_list
), gitem_list 
); 
 542         gtk_list_insert_items( GTK_LIST (m_list
), gitem_list
, pos 
); 
 544     gtk_signal_connect( GTK_OBJECT(list_item
), "select", 
 545       GTK_SIGNAL_FUNC(gtk_listitem_select_callback
), (gpointer
)this ); 
 547     if (HasFlag(wxLB_MULTIPLE
) || HasFlag(wxLB_EXTENDED
)) 
 548         gtk_signal_connect( GTK_OBJECT(list_item
), "deselect", 
 549           GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback
), (gpointer
)this ); 
 551     gtk_signal_connect( GTK_OBJECT(list_item
), 
 552                         "button_press_event", 
 553                         (GtkSignalFunc
)gtk_listbox_button_press_callback
, 
 556     gtk_signal_connect_after( GTK_OBJECT(list_item
), 
 557                         "button_release_event", 
 558                         (GtkSignalFunc
)gtk_listbox_button_release_callback
, 
 561     gtk_signal_connect( GTK_OBJECT(list_item
), 
 563                            (GtkSignalFunc
)gtk_listbox_key_press_callback
, 
 566     ConnectWidget( list_item 
); 
 568     gtk_widget_show( list_item 
); 
 570     if (GTK_WIDGET_REALIZED(m_widget
)) 
 572         gtk_widget_realize( list_item 
); 
 573         gtk_widget_realize( GTK_BIN(list_item
)->child 
); 
 575         // Apply current widget style to the new list_item 
 578             gtk_widget_set_style( GTK_WIDGET( list_item 
), m_widgetStyle 
); 
 579             GtkBin 
*bin 
= GTK_BIN( list_item 
); 
 580             GtkWidget 
*label 
= GTK_WIDGET( bin
->child 
); 
 581             gtk_widget_set_style( label
, m_widgetStyle 
); 
 585         if (m_tooltip
) m_tooltip
->Apply( this ); 
 590 void wxListBox::DoSetItems( const wxArrayString
& items
, 
 595     DoInsertItems(items
, 0); 
 599         size_t count 
= items
.GetCount(); 
 600         for ( size_t n 
= 0; n 
< count
; n
++ ) 
 602             SetClientData(n
, clientData
[n
]); 
 607 // ---------------------------------------------------------------------------- 
 609 // ---------------------------------------------------------------------------- 
 611 void wxListBox::DoSetItemClientData( int n
, void* clientData 
) 
 613     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid listbox control") ); 
 615     wxNode 
*node 
= m_clientList
.Nth( n 
); 
 616     wxCHECK_RET( node
, wxT("invalid index in wxListBox::DoSetItemClientData") ); 
 618     node
->SetData( (wxObject
*) clientData 
); 
 621 void* wxListBox::DoGetItemClientData( int n 
) const 
 623     wxCHECK_MSG( m_widget 
!= NULL
, NULL
, wxT("invalid listbox control") ); 
 625     wxNode 
*node 
= m_clientList
.Nth( n 
); 
 626     wxCHECK_MSG( node
, NULL
, wxT("invalid index in wxListBox::DoGetItemClientData") ); 
 631 void wxListBox::DoSetItemClientObject( int n
, wxClientData
* clientData 
) 
 633     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid listbox control") ); 
 635     wxNode 
*node 
= m_clientList
.Nth( n 
); 
 636     wxCHECK_RET( node
, wxT("invalid index in wxListBox::DoSetItemClientObject") ); 
 638     wxClientData 
*cd 
= (wxClientData
*) node
->Data(); 
 641     node
->SetData( (wxObject
*) clientData 
); 
 644 wxClientData
* wxListBox::DoGetItemClientObject( int n 
) const 
 646     wxCHECK_MSG( m_widget 
!= NULL
, (wxClientData
*) NULL
, wxT("invalid listbox control") ); 
 648     wxNode 
*node 
= m_clientList
.Nth( n 
); 
 649     wxCHECK_MSG( node
, (wxClientData 
*)NULL
, 
 650                  wxT("invalid index in wxListBox::DoGetItemClientObject") ); 
 652     return (wxClientData
*) node
->Data(); 
 655 void wxListBox::Clear() 
 657     wxCHECK_RET( m_list 
!= NULL
, wxT("invalid listbox") ); 
 659     gtk_list_clear_items( m_list
, 0, GetCount() ); 
 661     if ( GTK_LIST(m_list
)->last_focus_child 
!= NULL  
) 
 663         // This should be NULL, I think. 
 664         GTK_LIST(m_list
)->last_focus_child 
= NULL
; 
 667     if ( HasClientObjectData() ) 
 669         // destroy the data (due to Robert's idea of using wxList<wxObject> 
 670         // and not wxList<wxClientData> we can't just say 
 671         // m_clientList.DeleteContents(TRUE) - this would crash! 
 672         wxNode 
*node 
= m_clientList
.First(); 
 675             delete (wxClientData 
*)node
->Data(); 
 679     m_clientList
.Clear(); 
 685 void wxListBox::Delete( int n 
) 
 687     wxCHECK_RET( m_list 
!= NULL
, wxT("invalid listbox") ); 
 689     GList 
*child 
= g_list_nth( m_list
->children
, n 
); 
 691     wxCHECK_RET( child
, wxT("wrong listbox index") ); 
 693     GList 
*list 
= g_list_append( (GList
*) NULL
, child
->data 
); 
 694     gtk_list_remove_items( m_list
, list 
); 
 697     wxNode 
*node 
= m_clientList
.Nth( n 
); 
 700         if ( m_clientDataItemsType 
== wxClientData_Object 
) 
 702             wxClientData 
*cd 
= (wxClientData
*)node
->Data(); 
 706         m_clientList
.DeleteNode( node 
); 
 710         m_strings
->Remove(n
); 
 713 // ---------------------------------------------------------------------------- 
 714 // string list access 
 715 // ---------------------------------------------------------------------------- 
 717 void wxListBox::SetString( int n
, const wxString 
&string 
) 
 719     wxCHECK_RET( m_list 
!= NULL
, wxT("invalid listbox") ); 
 721     GList 
*child 
= g_list_nth( m_list
->children
, n 
); 
 724         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 725         GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 728 #if wxUSE_CHECKLISTBOX 
 730             str 
+= wxCHECKLBOX_STRING
; 
 731 #endif // wxUSE_CHECKLISTBOX 
 734         gtk_label_set( label
, str
.mbc_str() ); 
 738         wxFAIL_MSG(wxT("wrong listbox index")); 
 742 wxString 
wxListBox::GetString( int n 
) const 
 744     wxCHECK_MSG( m_list 
!= NULL
, wxT(""), wxT("invalid listbox") ); 
 746     GList 
*child 
= g_list_nth( m_list
->children
, n 
); 
 749         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 750         GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 752         wxString str 
= wxString(GET_REAL_LABEL(label
->label
),*wxConvCurrent
); 
 757     wxFAIL_MSG(wxT("wrong listbox index")); 
 762 int wxListBox::GetCount() const 
 764     wxCHECK_MSG( m_list 
!= NULL
, -1, wxT("invalid listbox") ); 
 766     GList 
*children 
= m_list
->children
; 
 767     return g_list_length(children
); 
 770 int wxListBox::FindString( const wxString 
&item 
) const 
 772     wxCHECK_MSG( m_list 
!= NULL
, -1, wxT("invalid listbox") ); 
 774     GList 
*child 
= m_list
->children
; 
 778         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 779         GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 781         wxString str 
= wxString(GET_REAL_LABEL(label
->label
),*wxConvCurrent
); 
 790     // it's not an error if the string is not found -> no wxCHECK 
 795 // ---------------------------------------------------------------------------- 
 797 // ---------------------------------------------------------------------------- 
 799 int wxListBox::GetSelection() const 
 801     wxCHECK_MSG( m_list 
!= NULL
, -1, wxT("invalid listbox") ); 
 803     GList 
*child 
= m_list
->children
; 
 807         if (GTK_WIDGET(child
->data
)->state 
== GTK_STATE_SELECTED
) return count
; 
 814 int wxListBox::GetSelections( wxArrayInt
& aSelections 
) const 
 816     wxCHECK_MSG( m_list 
!= NULL
, -1, wxT("invalid listbox") ); 
 818     // get the number of selected items first 
 819     GList 
*child 
= m_list
->children
; 
 821     for (child 
= m_list
->children
; child 
!= NULL
; child 
= child
->next
) 
 823         if (GTK_WIDGET(child
->data
)->state 
== GTK_STATE_SELECTED
) 
 832         aSelections
.Alloc(count
); // optimization attempt 
 834         for (child 
= m_list
->children
; child 
!= NULL
; child 
= child
->next
, i
++) 
 836             if (GTK_WIDGET(child
->data
)->state 
== GTK_STATE_SELECTED
) 
 844 bool wxListBox::IsSelected( int n 
) const 
 846     wxCHECK_MSG( m_list 
!= NULL
, FALSE
, wxT("invalid listbox") ); 
 848     GList 
*target 
= g_list_nth( m_list
->children
, n 
); 
 850     wxCHECK_MSG( target
, FALSE
, wxT("invalid listbox index") ); 
 852     return (GTK_WIDGET(target
->data
)->state 
== GTK_STATE_SELECTED
) ; 
 855 void wxListBox::SetSelection( int n
, bool select 
) 
 857     wxCHECK_RET( m_list 
!= NULL
, wxT("invalid listbox") ); 
 863         if ((m_windowStyle 
& wxLB_SINGLE
) != 0) 
 864             gtk_list_unselect_item( m_list
, m_prevSelection 
); 
 865         gtk_list_select_item( m_list
, n 
); 
 869         gtk_list_unselect_item( m_list
, n 
); 
 871     m_blockEvent 
= FALSE
;     
 874 void wxListBox::DoSetFirstItem( int n 
) 
 876     wxCHECK_RET( m_list
, wxT("invalid listbox") ); 
 878     if (gdk_pointer_is_grabbed () && GTK_WIDGET_HAS_GRAB (m_list
)) 
 881     // terribly efficient 
 882     const gchar 
*vadjustment_key 
= "gtk-vadjustment"; 
 883     guint vadjustment_key_id 
= g_quark_from_static_string (vadjustment_key
); 
 885     GtkAdjustment 
*adjustment 
= 
 886        (GtkAdjustment
*) gtk_object_get_data_by_id (GTK_OBJECT (m_list
), vadjustment_key_id
); 
 887     wxCHECK_RET( adjustment
, wxT("invalid listbox code") ); 
 889     GList 
*target 
= g_list_nth( m_list
->children
, n 
); 
 890     wxCHECK_RET( target
, wxT("invalid listbox index") ); 
 892     GtkWidget 
*item 
= GTK_WIDGET(target
->data
); 
 893     wxCHECK_RET( item
, wxT("invalid listbox code") ); 
 895     if (item
->allocation
.y 
== -1) 
 897         wxlistbox_idle_struct
* data 
= new wxlistbox_idle_struct
; 
 898         data
->m_listbox 
= this; 
 900         data
->m_tag 
= gtk_idle_add_priority( 800, wxlistbox_idle_callback
, (gpointer
) data 
); 
 905     float y 
= item
->allocation
.y
; 
 906     if (y 
> adjustment
->upper 
- adjustment
->page_size
) 
 907         y 
= adjustment
->upper 
- adjustment
->page_size
; 
 908         gtk_adjustment_set_value( adjustment
, y 
); 
 911 // ---------------------------------------------------------------------------- 
 913 // ---------------------------------------------------------------------------- 
 915 int wxListBox::GtkGetIndex( GtkWidget 
*item 
) const 
 919         GList 
*child 
= m_list
->children
; 
 923             if (GTK_WIDGET(child
->data
) == item
) return count
; 
 932 void wxListBox::ApplyToolTip( GtkTooltips 
*tips
, const wxChar 
*tip 
) 
 934     GList 
*child 
= m_list
->children
; 
 937         gtk_tooltips_set_tip( tips
, GTK_WIDGET( child
->data 
), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL 
); 
 941 #endif // wxUSE_TOOLTIPS 
 943 GtkWidget 
*wxListBox::GetConnectWidget() 
 945     return GTK_WIDGET(m_list
); 
 948 bool wxListBox::IsOwnGtkWindow( GdkWindow 
*window 
) 
 950     if (GTK_WIDGET(m_list
)->window 
== window
) return TRUE
; 
 952     GList 
*child 
= m_list
->children
; 
 955         GtkWidget 
*bin 
= GTK_WIDGET( child
->data 
); 
 956         if (bin
->window 
== window
) return TRUE
; 
 963 void wxListBox::ApplyWidgetStyle() 
 967     if (m_backgroundColour
.Ok()) 
 969         GdkWindow 
*window 
= GTK_WIDGET(m_list
)->window
; 
 972             m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window 
) ); 
 973             gdk_window_set_background( window
, m_backgroundColour
.GetColor() ); 
 974             gdk_window_clear( window 
); 
 978     GList 
*child 
= m_list
->children
; 
 981         gtk_widget_set_style( GTK_WIDGET(child
->data
), m_widgetStyle 
); 
 983         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 984         GtkWidget 
*label 
= GTK_WIDGET( bin
->child 
); 
 985         gtk_widget_set_style( label
, m_widgetStyle 
); 
 991 void wxListBox::OnInternalIdle() 
 993     wxCursor cursor 
= m_cursor
; 
 994     if (g_globalCursor
.Ok()) cursor 
= g_globalCursor
; 
 996     if (GTK_WIDGET(m_list
)->window 
&& cursor
.Ok()) 
 998         /* I now set the cursor the anew in every OnInternalIdle call 
 999            as setting the cursor in a parent window also effects the 
1000            windows above so that checking for the current cursor is 
1003         gdk_window_set_cursor( GTK_WIDGET(m_list
)->window
, cursor
.GetCursor() ); 
1005         GList 
*child 
= m_list
->children
; 
1008             GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
1009             GtkWidget 
*label 
= GTK_WIDGET( bin
->child 
); 
1014                 gdk_window_set_cursor( label
->window
, cursor
.GetCursor() ); 
1016             child 
= child
->next
; 
1023 wxSize 
wxListBox::DoGetBestSize() const 
1025     int lbWidth 
= 100;  // some defaults 
1029     // Find the widest line 
1030     for(int i 
= 0; i 
< GetCount(); i
++) { 
1031         wxString 
str(GetString(i
)); 
1032         GetTextExtent(str
, &wLine
, NULL
); 
1033         lbWidth 
= wxMax(lbWidth
, wLine
); 
1036     // Add room for the scrollbar 
1037     lbWidth 
+= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
); 
1039     // And just a bit more 
1041     GetTextExtent("X", &cx
, &cy
); 
1044     // don't make the listbox too tall (limit height to around 10 items) but don't 
1045     // make it too small neither 
1046     lbHeight 
= (cy
+4) * wxMin(wxMax(GetCount(), 3), 10); 
1048     return wxSize(lbWidth
, lbHeight
);