1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  12 #pragma implementation "listbox.h" 
  15 #include "wx/dynarray.h" 
  16 #include "wx/listbox.h" 
  19 #include "wx/checklst.h" 
  21 //------------------------------------------------------------------------- 
  22 // conditional compilation 
  23 //------------------------------------------------------------------------- 
  25 #if (GTK_MINOR_VERSION == 1) 
  26 #if (GTK_MICRO_VERSION >= 5) 
  27 #define NEW_GTK_SCROLL_CODE 
  31 //----------------------------------------------------------------------------- 
  33 //----------------------------------------------------------------------------- 
  35 extern bool   g_blockEventsOnDrag
; 
  36 extern bool   g_blockEventsOnScroll
; 
  38 //----------------------------------------------------------------------------- 
  39 // "button_press_event" 
  40 //----------------------------------------------------------------------------- 
  43 gtk_listbox_button_press_callback( GtkWidget 
*widget
, GdkEventButton 
*gdk_event
, wxListBox 
*listbox 
) 
  45     if (g_blockEventsOnDrag
) return FALSE
; 
  46     if (g_blockEventsOnScroll
) return FALSE
; 
  48     if (!listbox
->HasVMT()) return FALSE
; 
  50     if (gdk_event
->x 
> 15) return FALSE
; 
  52     int sel 
= listbox
->GetIndex( widget 
); 
  54     wxCheckListBox 
*clb 
= (wxCheckListBox 
*)listbox
; 
  56     clb
->Check( sel
, !clb
->IsChecked(sel
) ); 
  61 //----------------------------------------------------------------------------- 
  62 // "select" and "deselect" 
  63 //----------------------------------------------------------------------------- 
  65 static void gtk_listitem_select_callback( GtkWidget 
*WXUNUSED(widget
), wxListBox 
*listbox 
) 
  67     if (!listbox
->HasVMT()) return; 
  68     if (g_blockEventsOnDrag
) return; 
  70     wxCommandEvent 
event(wxEVT_COMMAND_LISTBOX_SELECTED
, listbox
->GetId() ); 
  72     wxArrayInt aSelections
; 
  73     int count 
= listbox
->GetSelections(aSelections
); 
  76         event
.m_commandInt 
= aSelections
[0] ; 
  77         event
.m_clientData 
= listbox
->GetClientData( event
.m_commandInt 
); 
  78         wxString 
str(listbox
->GetString(event
.m_commandInt
)); 
  79         if (str 
!= "") event
.m_commandString 
= copystring((char *)(const char *)str
); 
  83         event
.m_commandInt 
= -1 ; 
  84         event
.m_commandString 
= copystring("") ; 
  87     event
.SetEventObject( listbox 
); 
  89     listbox
->GetEventHandler()->ProcessEvent( event 
); 
  90     if (event
.m_commandString
) delete[] event
.m_commandString 
; 
  93 //----------------------------------------------------------------------------- 
  95 //----------------------------------------------------------------------------- 
  97 IMPLEMENT_DYNAMIC_CLASS(wxListBox
,wxControl
) 
  99 wxListBox::wxListBox() 
 101     m_list 
= (GtkList 
*) NULL
; 
 102     m_hasCheckBoxes 
= FALSE
; 
 105 bool wxListBox::Create( wxWindow 
*parent
, wxWindowID id
, 
 106                         const wxPoint 
&pos
, const wxSize 
&size
, 
 107                         int n
, const wxString choices
[], 
 108                         long style
, const wxValidator
& validator
, const wxString 
&name 
) 
 112     PreCreation( parent
, id
, pos
, size
, style
, name 
); 
 114     SetValidator( validator 
); 
 116     m_widget 
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL 
); 
 117     gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget
), 
 118       GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC 
); 
 120     m_list 
= GTK_LIST( gtk_list_new() ); 
 122     GtkSelectionMode mode 
= GTK_SELECTION_BROWSE
; 
 123     if (style 
& wxLB_MULTIPLE
) 
 124         mode 
= GTK_SELECTION_MULTIPLE
; 
 125     else if (style 
& wxLB_EXTENDED
) 
 126         mode 
= GTK_SELECTION_EXTENDED
; 
 128     gtk_list_set_selection_mode( GTK_LIST(m_list
), mode 
); 
 130 #ifdef NEW_GTK_SCROLL_CODE 
 131     gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(m_widget
), GTK_WIDGET(m_list
) ); 
 133     gtk_container_add( GTK_CONTAINER(m_widget
), GTK_WIDGET(m_list
) ); 
 136     gtk_widget_show( GTK_WIDGET(m_list
) ); 
 138     wxSize newSize 
= size
; 
 139     if (newSize
.x 
== -1) newSize
.x 
= 100; 
 140     if (newSize
.y 
== -1) newSize
.y 
= 110; 
 141     SetSize( newSize
.x
, newSize
.y 
); 
 143     for (int i 
= 0; i 
< n
; i
++) 
 145         m_clientDataList
.Append( (wxObject
*) NULL 
); 
 146         m_clientObjectList
.Append( (wxObject
*) NULL 
); 
 148         GtkWidget 
*list_item
; 
 152             wxString str 
= "[-] "; 
 154             list_item 
= gtk_list_item_new_with_label( str 
); 
 158             list_item 
= gtk_list_item_new_with_label( choices
[i
] ); 
 161         gtk_container_add( GTK_CONTAINER(m_list
), list_item 
); 
 163         gtk_signal_connect( GTK_OBJECT(list_item
), "select", 
 164           GTK_SIGNAL_FUNC(gtk_listitem_select_callback
), (gpointer
)this ); 
 166         if (style 
& wxLB_MULTIPLE
) 
 167             gtk_signal_connect( GTK_OBJECT(list_item
), "deselect", 
 168               GTK_SIGNAL_FUNC(gtk_listitem_select_callback
), (gpointer
)this ); 
 172             gtk_signal_connect( GTK_OBJECT(list_item
),  
 173                                 "button_press_event", 
 174                                 (GtkSignalFunc
)gtk_listbox_button_press_callback
,  
 178         ConnectWidget( list_item 
);      
 180         gtk_widget_show( list_item 
); 
 183     m_parent
->AddChild( this ); 
 185     (m_parent
->m_insertCallback
)( m_parent
, this ); 
 189     gtk_widget_realize( GTK_WIDGET(m_list
) ); 
 191     SetBackgroundColour( parent
->GetBackgroundColour() ); 
 192     SetForegroundColour( parent
->GetForegroundColour() ); 
 199 wxListBox::~wxListBox() 
 204 void wxListBox::AppendCommon( const wxString 
&item 
) 
 206     wxCHECK_RET( m_list 
!= NULL
, "invalid listbox" ); 
 208     GtkWidget 
*list_item
; 
 212         wxString str 
= "[-] "; 
 214         list_item 
= gtk_list_item_new_with_label( str 
); 
 218         list_item 
= gtk_list_item_new_with_label( item 
); 
 221     gtk_signal_connect( GTK_OBJECT(list_item
), "select", 
 222       GTK_SIGNAL_FUNC(gtk_listitem_select_callback
), (gpointer
)this ); 
 224     if (GetWindowStyleFlag() & wxLB_MULTIPLE
) 
 225         gtk_signal_connect( GTK_OBJECT(list_item
), "deselect", 
 226           GTK_SIGNAL_FUNC(gtk_listitem_select_callback
), (gpointer
)this ); 
 228     gtk_container_add( GTK_CONTAINER(m_list
), list_item 
); 
 230     if (m_widgetStyle
) ApplyWidgetStyle(); 
 234             gtk_signal_connect( GTK_OBJECT(list_item
),  
 235                                 "button_press_event", 
 236                                 (GtkSignalFunc
)gtk_listbox_button_press_callback
,  
 240     gtk_widget_show( list_item 
); 
 242     ConnectWidget( list_item 
); 
 244 #ifndef NEW_GTK_DND_CODE 
 245     if (m_dropTarget
) m_dropTarget
->RegisterWidget( list_item 
); 
 249 void wxListBox::Append( const wxString 
&item 
) 
 251     m_clientDataList
.Append( (wxObject
*) NULL 
); 
 252     m_clientObjectList
.Append( (wxObject
*) NULL 
); 
 254     AppendCommon( item 
); 
 257 void wxListBox::Append( const wxString 
&item
, void *clientData 
) 
 259     m_clientDataList
.Append( (wxObject
*) clientData 
); 
 260     m_clientObjectList
.Append( (wxObject
*) NULL 
); 
 262     AppendCommon( item 
); 
 265 void wxListBox::Append( const wxString 
&item
, wxClientData 
*clientData 
) 
 267     m_clientObjectList
.Append( (wxObject
*) clientData 
); 
 268     m_clientDataList
.Append( (wxObject
*) NULL 
); 
 270     AppendCommon( item 
); 
 273 void wxListBox::SetClientData( int n
, void* clientData 
) 
 275     wxCHECK_RET( m_widget 
!= NULL
, "invalid combobox" ); 
 277     wxNode 
*node 
= m_clientDataList
.Nth( n 
); 
 280     node
->SetData( (wxObject
*) clientData 
); 
 283 void* wxListBox::GetClientData( int n 
) 
 285     wxCHECK_MSG( m_widget 
!= NULL
, NULL
, "invalid combobox" ); 
 287     wxNode 
*node 
= m_clientDataList
.Nth( n 
); 
 288     if (!node
) return NULL
; 
 293 void wxListBox::SetClientObject( int n
, wxClientData
* clientData 
) 
 295     wxCHECK_RET( m_widget 
!= NULL
, "invalid combobox" ); 
 297     wxNode 
*node 
= m_clientObjectList
.Nth( n 
); 
 300     wxClientData 
*cd 
= (wxClientData
*) node
->Data(); 
 303     node
->SetData( (wxObject
*) clientData 
); 
 306 wxClientData
* wxListBox::GetClientObject( int n 
) 
 308     wxCHECK_MSG( m_widget 
!= NULL
, (wxClientData
*)NULL
, "invalid combobox" ); 
 310     wxNode 
*node 
= m_clientObjectList
.Nth( n 
); 
 311     if (!node
) return (wxClientData
*) NULL
; 
 313     return (wxClientData
*) node
->Data(); 
 316 void wxListBox::Clear() 
 318     wxCHECK_RET( m_list 
!= NULL
, "invalid listbox" ); 
 320     gtk_list_clear_items( m_list
, 0, Number() ); 
 322     wxNode 
*node 
= m_clientObjectList
.First(); 
 325         wxClientData 
*cd 
= (wxClientData
*)node
->Data(); 
 329     m_clientObjectList
.Clear(); 
 331     m_clientDataList
.Clear(); 
 334 void wxListBox::Delete( int n 
) 
 336     wxCHECK_RET( m_list 
!= NULL
, "invalid listbox" ); 
 338     GList 
*child 
= g_list_nth( m_list
->children
, n 
); 
 340     wxCHECK_RET( child
, "wrong listbox index" ); 
 342     GList 
*list 
= g_list_append( NULL
, child
->data 
); 
 343     gtk_list_remove_items( m_list
, list 
); 
 346     wxNode 
*node 
= m_clientObjectList
.Nth( n 
); 
 349         wxClientData 
*cd 
= (wxClientData
*)node
->Data(); 
 351         m_clientObjectList
.DeleteNode( node 
); 
 354     node 
= m_clientDataList
.Nth( n 
); 
 357         m_clientDataList
.DeleteNode( node 
); 
 361 void wxListBox::Deselect( int n 
) 
 363     wxCHECK_RET( m_list 
!= NULL
, "invalid listbox" ); 
 365     gtk_list_unselect_item( m_list
, n 
); 
 368 int wxListBox::FindString( const wxString 
&item 
) const 
 370     wxCHECK_MSG( m_list 
!= NULL
, -1, "invalid listbox" ); 
 372     GList 
*child 
= m_list
->children
; 
 376         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 377         GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 379         wxString str 
= label
->label
; 
 380         if (m_hasCheckBoxes
) str
.Remove( 0, 4 ); 
 382         if (str 
== item
) return count
; 
 388   // it's not an error if the string is not found -> no wxCHECK 
 393 int wxListBox::GetSelection() const 
 395     wxCHECK_MSG( m_list 
!= NULL
, -1, "invalid listbox" ); 
 397     GList 
*child 
= m_list
->children
; 
 401         if (GTK_WIDGET(child
->data
)->state 
== GTK_STATE_SELECTED
) return count
; 
 408 int wxListBox::GetSelections( wxArrayInt
& aSelections 
) const 
 410     wxCHECK_MSG( m_list 
!= NULL
, -1, "invalid listbox" ); 
 412     // get the number of selected items first 
 413     GList 
*child 
= m_list
->children
; 
 415     for (child 
= m_list
->children
; child 
!= NULL
; child 
= child
->next
) 
 417         if (GTK_WIDGET(child
->data
)->state 
== GTK_STATE_SELECTED
) 
 426         aSelections
.Alloc(count
); // optimization attempt 
 428         for (child 
= m_list
->children
; child 
!= NULL
; child 
= child
->next
, i
++) 
 430             if (GTK_WIDGET(child
->data
)->state 
== GTK_STATE_SELECTED
) 
 438 wxString 
wxListBox::GetString( int n 
) const 
 440     wxCHECK_MSG( m_list 
!= NULL
, "", "invalid listbox" ); 
 442     GList 
*child 
= g_list_nth( m_list
->children
, n 
); 
 445         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 446         GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 448         wxString str 
= label
->label
; 
 449         if (m_hasCheckBoxes
) str
.Remove( 0, 4 ); 
 453     wxFAIL_MSG("wrong listbox index"); 
 457 wxString 
wxListBox::GetStringSelection() const 
 459     wxCHECK_MSG( m_list 
!= NULL
, "", "invalid listbox" ); 
 461     GList 
*selection 
= m_list
->selection
; 
 464         GtkBin 
*bin 
= GTK_BIN( selection
->data 
); 
 465         GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 467         wxString str 
= label
->label
; 
 468         if (m_hasCheckBoxes
) str
.Remove( 0, 4 ); 
 473     wxFAIL_MSG("no listbox selection available"); 
 477 int wxListBox::Number() 
 479     wxCHECK_MSG( m_list 
!= NULL
, -1, "invalid listbox" ); 
 481     GList 
*child 
= m_list
->children
; 
 483     while (child
) { count
++; child 
= child
->next
; } 
 487 bool wxListBox::Selected( int n 
) 
 489     wxCHECK_MSG( m_list 
!= NULL
, FALSE
, "invalid listbox" ); 
 491     GList 
*target 
= g_list_nth( m_list
->children
, n 
); 
 494         GList 
*child 
= m_list
->selection
; 
 497             if (child
->data 
== target
->data
) return TRUE
; 
 501     wxFAIL_MSG("wrong listbox index"); 
 505 void wxListBox::Set( int WXUNUSED(n
), const wxString 
*WXUNUSED(choices
) ) 
 507     wxFAIL_MSG("wxListBox::Set not implemented"); 
 510 void wxListBox::SetFirstItem( int WXUNUSED(n
) ) 
 512     wxFAIL_MSG("wxListBox::SetFirstItem not implemented"); 
 515 void wxListBox::SetFirstItem( const wxString 
&WXUNUSED(item
) ) 
 517     wxFAIL_MSG("wxListBox::SetFirstItem not implemented"); 
 520 void wxListBox::SetSelection( int n
, bool select 
) 
 522     wxCHECK_RET( m_list 
!= NULL
, "invalid listbox" ); 
 525         gtk_list_select_item( m_list
, n 
); 
 527         gtk_list_unselect_item( m_list
, n 
); 
 530 void wxListBox::SetString( int n
, const wxString 
&string 
) 
 532     wxCHECK_RET( m_list 
!= NULL
, "invalid listbox" ); 
 534     GList 
*child 
= g_list_nth( m_list
->children
, n 
); 
 537         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 538         GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 541         if (m_hasCheckBoxes
) str 
+= "[-] "; 
 544         gtk_label_set( label
, str 
); 
 548         wxFAIL_MSG("wrong listbox index"); 
 552 void wxListBox::SetStringSelection( const wxString 
&string
, bool select 
) 
 554     wxCHECK_RET( m_list 
!= NULL
, "invalid listbox" ); 
 556     SetSelection( FindString(string
), select 
); 
 559 int wxListBox::GetIndex( GtkWidget 
*item 
) const 
 563         GList 
*child 
= m_list
->children
; 
 567             if (GTK_WIDGET(child
->data
) == item
) return count
; 
 575 void wxListBox::SetDropTarget( wxDropTarget 
*dropTarget 
) 
 577     wxCHECK_RET( m_list 
!= NULL
, "invalid listbox" ); 
 579 #ifndef NEW_GTK_DND_CODE 
 582         GList 
*child 
= m_list
->children
; 
 585             m_dropTarget
->UnregisterWidget( GTK_WIDGET( child
->data 
) ); 
 591     wxWindow::SetDropTarget( dropTarget 
); 
 593 #ifndef NEW_GTK_DND_CODE 
 596         GList 
*child 
= m_list
->children
; 
 599             m_dropTarget
->RegisterWidget( GTK_WIDGET( child
->data 
) ); 
 606 GtkWidget 
*wxListBox::GetConnectWidget() 
 608     return GTK_WIDGET(m_list
); 
 611 bool wxListBox::IsOwnGtkWindow( GdkWindow 
*window 
) 
 613     if (wxWindow::IsOwnGtkWindow( window 
)) return TRUE
; 
 615     GList 
*child 
= m_list
->children
; 
 618         GtkWidget 
*bin 
= GTK_WIDGET( child
->data 
); 
 619         if (bin
->window 
== window
) return TRUE
; 
 626 void wxListBox::ApplyWidgetStyle() 
 630     if (m_backgroundColour
.Ok()) 
 632         GdkWindow 
*window 
= GTK_WIDGET(m_list
)->window
; 
 633         m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window 
) ); 
 634         gdk_window_set_background( window
, m_backgroundColour
.GetColor() ); 
 635         gdk_window_clear( window 
); 
 638     GList 
*child 
= m_list
->children
; 
 641         gtk_widget_set_style( GTK_WIDGET(child
->data
), m_widgetStyle 
); 
 643         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 644         GtkWidget 
*label 
= GTK_WIDGET( bin
->child 
); 
 645         gtk_widget_set_style( label
, m_widgetStyle 
);