1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  11 #pragma implementation "combobox.h" 
  14 #include "wx/combobox.h" 
  18 #include "wx/settings.h" 
  25 //----------------------------------------------------------------------------- 
  27 //----------------------------------------------------------------------------- 
  29 extern void wxapp_install_idle_handler(); 
  32 //----------------------------------------------------------------------------- 
  34 //----------------------------------------------------------------------------- 
  36 extern bool   g_blockEventsOnDrag
; 
  38 //----------------------------------------------------------------------------- 
  40 //----------------------------------------------------------------------------- 
  43 gtk_combo_clicked_callback( GtkWidget 
*WXUNUSED(widget
), wxComboBox 
*combo 
) 
  45     if (g_isIdle
) wxapp_install_idle_handler(); 
  47     if (!combo
->m_hasVMT
) return; 
  49     if (g_blockEventsOnDrag
) return; 
  51     if (combo
->m_alreadySent
) 
  53         combo
->m_alreadySent 
= FALSE
; 
  57     combo
->m_alreadySent 
= TRUE
; 
  59     wxCommandEvent 
event( wxEVT_COMMAND_COMBOBOX_SELECTED
, combo
->GetId() ); 
  60     event
.SetInt( combo
->GetSelection() ); 
  61     event
.SetString( combo
->GetStringSelection() ); 
  62     event
.SetEventObject( combo 
); 
  64     combo
->GetEventHandler()->ProcessEvent( event 
); 
  67 //----------------------------------------------------------------------------- 
  69 //----------------------------------------------------------------------------- 
  72 gtk_text_changed_callback( GtkWidget 
*WXUNUSED(widget
), wxComboBox 
*combo 
) 
  74     if (g_isIdle
) wxapp_install_idle_handler(); 
  76     if (!combo
->m_hasVMT
) return; 
  78     wxCommandEvent 
event( wxEVT_COMMAND_TEXT_UPDATED
, combo
->GetId() ); 
  79     event
.SetString( combo
->GetValue() ); 
  80     event
.SetEventObject( combo 
); 
  81     combo
->GetEventHandler()->ProcessEvent( event 
); 
  84 //----------------------------------------------------------------------------- 
  86 //----------------------------------------------------------------------------- 
  88 IMPLEMENT_DYNAMIC_CLASS(wxComboBox
,wxControl
) 
  90 BEGIN_EVENT_TABLE(wxComboBox
, wxControl
) 
  91     EVT_SIZE(wxComboBox::OnSize
) 
  92     EVT_CHAR(wxComboBox::OnChar
) 
  95 bool wxComboBox::Create( wxWindow 
*parent
, wxWindowID id
, const wxString
& value
, 
  96                          const wxPoint
& pos
, const wxSize
& size
, 
  97                          int n
, const wxString choices
[], 
  98                          long style
, const wxValidator
& validator
, 
  99                          const wxString
& name 
) 
 101     m_alreadySent 
= FALSE
; 
 103     m_acceptsFocus 
= TRUE
; 
 105     PreCreation( parent
, id
, pos
, size
, style
, name 
); 
 107     SetValidator( validator 
); 
 109     m_widget 
= gtk_combo_new(); 
 111     // make it more useable 
 112     gtk_combo_set_use_arrows_always(GTK_COMBO(m_widget
), TRUE
); 
 114     wxSize newSize 
= size
; 
 119     SetSize( newSize
.x
, newSize
.y 
); 
 121     GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 123     for (int i 
= 0; i 
< n
; i
++) 
 125         /* don't send first event, which GTK sends aways when 
 126            inserting the first item */ 
 127         m_alreadySent 
= TRUE
; 
 129         GtkWidget 
*list_item 
= gtk_list_item_new_with_label( choices
[i
].mbc_str() ); 
 131         m_clientDataList
.Append( (wxObject
*)NULL 
); 
 132         m_clientObjectList
.Append( (wxObject
*)NULL 
); 
 134         gtk_container_add( GTK_CONTAINER(list
), list_item 
); 
 136         gtk_signal_connect( GTK_OBJECT(list_item
), "select", 
 137            GTK_SIGNAL_FUNC(gtk_combo_clicked_callback
), (gpointer
)this ); 
 139         gtk_widget_show( list_item 
); 
 142     m_parent
->DoAddChild( this ); 
 146     ConnectWidget( GTK_COMBO(m_widget
)->button 
); 
 148     if (!value
.IsNull()) SetValue( value 
); 
 150     if (style 
& wxCB_READONLY
) 
 151         gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
), FALSE 
); 
 153     gtk_signal_connect( GTK_OBJECT(GTK_COMBO(m_widget
)->entry
), "changed", 
 154       GTK_SIGNAL_FUNC(gtk_text_changed_callback
), (gpointer
)this); 
 156     SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOW 
) ); 
 157     SetForegroundColour( parent
->GetForegroundColour() ); 
 158     SetFont( parent
->GetFont() ); 
 165 wxComboBox::~wxComboBox() 
 167     wxNode 
*node 
= m_clientDataList
.First(); 
 170         wxClientData 
*cd 
= (wxClientData
*)node
->Data(); 
 174     m_clientDataList
.Clear(); 
 177 void wxComboBox::AppendCommon( const wxString 
&item 
) 
 179     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 181     GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 183     GtkWidget 
*list_item 
= gtk_list_item_new_with_label( item
.mbc_str() ); 
 185     gtk_container_add( GTK_CONTAINER(list
), list_item 
); 
 187     gtk_signal_connect( GTK_OBJECT(list_item
), "select", 
 188       GTK_SIGNAL_FUNC(gtk_combo_clicked_callback
), (gpointer
)this ); 
 190     if (GTK_WIDGET_REALIZED(m_widget
)) 
 192         gtk_widget_realize( list_item 
); 
 193         gtk_widget_realize( GTK_BIN(list_item
)->child 
); 
 195         if (m_widgetStyle
) ApplyWidgetStyle(); 
 198     gtk_widget_show( list_item 
); 
 201 void wxComboBox::Append( const wxString 
&item 
) 
 203     m_clientDataList
.Append( (wxObject
*) NULL 
); 
 204     m_clientObjectList
.Append( (wxObject
*) NULL 
); 
 206     AppendCommon( item 
); 
 209 void wxComboBox::Append( const wxString 
&item
, void *clientData 
) 
 211     m_clientDataList
.Append( (wxObject
*) clientData 
); 
 212     m_clientObjectList
.Append( (wxObject
*)NULL 
); 
 214     AppendCommon( item 
); 
 217 void wxComboBox::Append( const wxString 
&item
, wxClientData 
*clientData 
) 
 219     m_clientDataList
.Append( (wxObject
*) NULL 
); 
 220     m_clientObjectList
.Append( (wxObject
*) clientData 
); 
 222     AppendCommon( item 
); 
 225 void wxComboBox::SetClientData( int n
, void* clientData 
) 
 227     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 229     wxNode 
*node 
= m_clientDataList
.Nth( n 
); 
 232     node
->SetData( (wxObject
*) clientData 
); 
 235 void* wxComboBox::GetClientData( int n 
) 
 237     wxCHECK_MSG( m_widget 
!= NULL
, NULL
, _T("invalid combobox") ); 
 239     wxNode 
*node 
= m_clientDataList
.Nth( n 
); 
 240     if (!node
) return NULL
; 
 245 void wxComboBox::SetClientObject( int n
, wxClientData
* clientData 
) 
 247     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 249     wxNode 
*node 
= m_clientObjectList
.Nth( n 
); 
 252     wxClientData 
*cd 
= (wxClientData
*) node
->Data(); 
 255     node
->SetData( (wxObject
*) clientData 
); 
 258 wxClientData
* wxComboBox::GetClientObject( int n 
) 
 260     wxCHECK_MSG( m_widget 
!= NULL
, (wxClientData
*)NULL
, _T("invalid combobox") ); 
 262     wxNode 
*node 
= m_clientDataList
.Nth( n 
); 
 263     if (!node
) return (wxClientData
*) NULL
; 
 265     return (wxClientData
*) node
->Data(); 
 268 void wxComboBox::Clear() 
 270     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 272     GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 273     gtk_list_clear_items( GTK_LIST(list
), 0, Number() ); 
 275     wxNode 
*node 
= m_clientObjectList
.First(); 
 278         wxClientData 
*cd 
= (wxClientData
*)node
->Data(); 
 282     m_clientObjectList
.Clear(); 
 284     m_clientDataList
.Clear(); 
 287 void wxComboBox::Delete( int n 
) 
 289     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 291     GtkList 
*listbox 
= GTK_LIST( GTK_COMBO(m_widget
)->list 
); 
 293     GList 
*child 
= g_list_nth( listbox
->children
, n 
); 
 297         wxFAIL_MSG(_T("wrong index")); 
 301     GList 
*list 
= g_list_append( (GList
*) NULL
, child
->data 
); 
 302     gtk_list_remove_items( listbox
, list 
); 
 305     wxNode 
*node 
= m_clientObjectList
.Nth( n 
); 
 308         wxClientData 
*cd 
= (wxClientData
*)node
->Data(); 
 310         m_clientObjectList
.DeleteNode( node 
); 
 313     node 
= m_clientDataList
.Nth( n 
); 
 316         m_clientDataList
.DeleteNode( node 
); 
 320 int wxComboBox::FindString( const wxString 
&item 
) 
 322     wxCHECK_MSG( m_widget 
!= NULL
, -1, _T("invalid combobox") ); 
 324     GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 326     GList 
*child 
= GTK_LIST(list
)->children
; 
 330         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 331         GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 332         if (item 
== wxString(label
->label
,*wxConvCurrent
)) 
 341 int wxComboBox::GetSelection() const 
 343     wxCHECK_MSG( m_widget 
!= NULL
, -1, _T("invalid combobox") ); 
 345     GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 347     GList 
*selection 
= GTK_LIST(list
)->selection
; 
 350         GList 
*child 
= GTK_LIST(list
)->children
; 
 354             if (child
->data 
== selection
->data
) return count
; 
 360     wxFAIL_MSG( _T("wxComboBox: no selection") ); 
 365 wxString 
wxComboBox::GetString( int n 
) const 
 367     wxCHECK_MSG( m_widget 
!= NULL
, _T(""), _T("invalid combobox") ); 
 369     GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 372     GList 
*child 
= g_list_nth( GTK_LIST(list
)->children
, n 
); 
 375         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 376         GtkLabel 
*label 
= GTK_LABEL( bin
->child 
); 
 377         str 
= wxString(label
->label
,*wxConvCurrent
); 
 381         wxFAIL_MSG( _T("wxComboBox: wrong index") ); 
 387 wxString 
wxComboBox::GetStringSelection() const 
 389     wxCHECK_MSG( m_widget 
!= NULL
, _T(""), _T("invalid combobox") ); 
 391     GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 393     GList 
*selection 
= GTK_LIST(list
)->selection
; 
 396         GtkBin 
*bin 
= GTK_BIN( selection
->data 
); 
 397         wxString tmp 
= wxString(GTK_LABEL( bin
->child 
)->label
,*wxConvCurrent
); 
 401     wxFAIL_MSG( _T("wxComboBox: no selection") ); 
 406 int wxComboBox::Number() const 
 408     wxCHECK_MSG( m_widget 
!= NULL
, 0, _T("invalid combobox") ); 
 410     GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 412     GList 
*child 
= GTK_LIST(list
)->children
; 
 414     while (child
) { count
++; child 
= child
->next
; } 
 418 void wxComboBox::SetSelection( int n 
) 
 420     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 422     GtkWidget 
*list 
= GTK_COMBO(m_widget
)->list
; 
 423     gtk_list_select_item( GTK_LIST(list
), n 
); 
 426 void wxComboBox::SetStringSelection( const wxString 
&string 
) 
 428     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 430     int res 
= FindString( string 
); 
 431     if (res 
== -1) return; 
 435 wxString 
wxComboBox::GetValue() const 
 437     GtkWidget 
*entry 
= GTK_COMBO(m_widget
)->entry
; 
 438     wxString tmp 
= wxString(gtk_entry_get_text( GTK_ENTRY(entry
) ),*wxConvCurrent
); 
 442 void wxComboBox::SetValue( const wxString
& value 
) 
 444     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 446     GtkWidget 
*entry 
= GTK_COMBO(m_widget
)->entry
; 
 447     wxString tmp 
= _T(""); 
 448     if (!value
.IsNull()) tmp 
= value
; 
 449     gtk_entry_set_text( GTK_ENTRY(entry
), tmp
.mbc_str() ); 
 452 void wxComboBox::Copy() 
 454     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 456     GtkWidget 
*entry 
= GTK_COMBO(m_widget
)->entry
; 
 457 #if (GTK_MINOR_VERSION > 0) 
 458     gtk_editable_copy_clipboard( GTK_EDITABLE(entry
) ); 
 460     gtk_editable_copy_clipboard( GTK_EDITABLE(entry
), 0 ); 
 464 void wxComboBox::Cut() 
 466     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 468     GtkWidget 
*entry 
= GTK_COMBO(m_widget
)->entry
; 
 469 #if (GTK_MINOR_VERSION > 0) 
 470     gtk_editable_cut_clipboard( GTK_EDITABLE(entry
) ); 
 472     gtk_editable_cut_clipboard( GTK_EDITABLE(entry
), 0 ); 
 476 void wxComboBox::Paste() 
 478     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 480     GtkWidget 
*entry 
= GTK_COMBO(m_widget
)->entry
; 
 481 #if (GTK_MINOR_VERSION > 0) 
 482     gtk_editable_paste_clipboard( GTK_EDITABLE(entry
) ); 
 484     gtk_editable_paste_clipboard( GTK_EDITABLE(entry
), 0 ); 
 488 void wxComboBox::SetInsertionPoint( long pos 
) 
 490     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 492     GtkWidget 
*entry 
= GTK_COMBO(m_widget
)->entry
; 
 493     gtk_entry_set_position( GTK_ENTRY(entry
), (int)pos 
); 
 496 void wxComboBox::SetInsertionPointEnd() 
 498     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 500     SetInsertionPoint( -1 ); 
 503 long wxComboBox::GetInsertionPoint() const 
 505     GtkWidget 
*entry 
= GTK_COMBO(m_widget
)->entry
; 
 506     return (long) GTK_EDITABLE(entry
)->current_pos
; 
 509 long wxComboBox::GetLastPosition() const 
 511     GtkWidget 
*entry 
= GTK_COMBO(m_widget
)->entry
; 
 512     int pos 
= GTK_ENTRY(entry
)->text_length
; 
 516 void wxComboBox::Replace( long from
, long to
, const wxString
& value 
) 
 518     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 519     // FIXME: not quite sure how to do this method right in multibyte mode 
 521     GtkWidget 
*entry 
= GTK_COMBO(m_widget
)->entry
; 
 522     gtk_editable_delete_text( GTK_EDITABLE(entry
), (gint
)from
, (gint
)to 
); 
 523     if (value
.IsNull()) return; 
 525     gtk_editable_insert_text( GTK_EDITABLE(entry
), value
.mbc_str(), value
.Length(), &pos 
); 
 528 void wxComboBox::Remove(long from
, long to
) 
 530     wxCHECK_RET( m_widget 
!= NULL
, _T("invalid combobox") ); 
 532     GtkWidget 
*entry 
= GTK_COMBO(m_widget
)->entry
; 
 533     gtk_editable_delete_text( GTK_EDITABLE(entry
), (gint
)from
, (gint
)to 
); 
 536 void wxComboBox::SetSelection( long from
, long to 
) 
 538     GtkWidget 
*entry 
= GTK_COMBO(m_widget
)->entry
; 
 539     gtk_editable_select_region( GTK_EDITABLE(entry
), (gint
)from
, (gint
)to 
); 
 542 void wxComboBox::SetEditable( bool editable 
) 
 544     GtkWidget 
*entry 
= GTK_COMBO(m_widget
)->entry
; 
 545     gtk_entry_set_editable( GTK_ENTRY(entry
), editable 
); 
 548 void wxComboBox::OnChar( wxKeyEvent 
&event 
) 
 550     if ( event
.KeyCode() == WXK_RETURN 
) 
 552         wxString value 
= GetValue(); 
 556             // make Enter generate "selected" event if there is only one item 
 557             // in the combobox - without it, it's impossible to select it at 
 559             wxCommandEvent 
event( wxEVT_COMMAND_COMBOBOX_SELECTED
, GetId() ); 
 561             event
.SetString( value 
); 
 562             event
.SetEventObject( this ); 
 563             GetEventHandler()->ProcessEvent( event 
); 
 567             // add the item to the list if it's not there yet 
 568             if ( FindString(value
) == wxNOT_FOUND 
) 
 572                 // and generate the selected event for it 
 573                 wxCommandEvent 
event( wxEVT_COMMAND_COMBOBOX_SELECTED
, GetId() ); 
 574                 event
.SetInt( Number() - 1 ); 
 575                 event
.SetString( value 
); 
 576                 event
.SetEventObject( this ); 
 577                 GetEventHandler()->ProcessEvent( event 
); 
 579             //else: do nothing, this will open the listbox 
 586 void wxComboBox::OnSize( wxSizeEvent 
&event 
) 
 593     gtk_widget_set_usize( GTK_COMBO(m_widget
)->entry
, m_width
-w
-1, m_height 
); 
 595     gtk_widget_set_uposition( GTK_COMBO(m_widget
)->button
, m_x
+m_width
-w
, m_y 
); 
 596     gtk_widget_set_usize( GTK_COMBO(m_widget
)->button
, w
, m_height 
); 
 599 void wxComboBox::ApplyWidgetStyle() 
 603 //    gtk_widget_set_style( GTK_COMBO(m_widget)->button, m_widgetStyle ); 
 604     gtk_widget_set_style( GTK_COMBO(m_widget
)->entry
, m_widgetStyle 
); 
 605     gtk_widget_set_style( GTK_COMBO(m_widget
)->list
, m_widgetStyle 
); 
 607     GtkList 
*list 
= GTK_LIST( GTK_COMBO(m_widget
)->list 
); 
 608     GList 
*child 
= list
->children
; 
 611         gtk_widget_set_style( GTK_WIDGET(child
->data
), m_widgetStyle 
); 
 613         GtkBin 
*bin 
= GTK_BIN(child
->data
); 
 614         gtk_widget_set_style( bin
->child
, m_widgetStyle 
); 
 620 GtkWidget
* wxComboBox::GetConnectWidget() 
 622     return GTK_COMBO(m_widget
)->entry
; 
 625 bool wxComboBox::IsOwnGtkWindow( GdkWindow 
*window 
) 
 627     return ( (window 
== GTK_ENTRY( GTK_COMBO(m_widget
)->entry 
)->text_area
) || 
 628              (window 
== GTK_COMBO(m_widget
)->button
->window 
) );