1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/choice.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 #include "wx/wxprec.h"
12 #if wxUSE_CHOICE || wxUSE_COMBOBOX
14 #include "wx/choice.h"
17 #include "wx/arrstr.h"
20 #include "wx/gtk/private.h"
23 // ----------------------------------------------------------------------------
25 // ----------------------------------------------------------------------------
30 gtk_choice_changed_callback( GtkWidget
*WXUNUSED(widget
), wxChoice
*choice
)
32 choice
->SendSelectionChangedEvent(wxEVT_COMMAND_CHOICE_SELECTED
);
37 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
41 IMPLEMENT_DYNAMIC_CLASS(wxChoice
, wxControlWithItems
)
46 m_stringCellIndex
= 0;
49 bool wxChoice::Create( wxWindow
*parent
, wxWindowID id
,
50 const wxPoint
&pos
, const wxSize
&size
,
51 const wxArrayString
& choices
,
52 long style
, const wxValidator
& validator
,
53 const wxString
&name
)
55 wxCArrayString
chs(choices
);
57 return Create( parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(),
58 style
, validator
, name
);
61 bool wxChoice::Create( wxWindow
*parent
, wxWindowID id
,
62 const wxPoint
&pos
, const wxSize
&size
,
63 int n
, const wxString choices
[],
64 long style
, const wxValidator
& validator
,
65 const wxString
&name
)
67 if (!PreCreation( parent
, pos
, size
) ||
68 !CreateBase( parent
, id
, pos
, size
, style
, validator
, name
))
70 wxFAIL_MSG( wxT("wxChoice creation failed") );
76 // if our m_strings != NULL, Append() will check for it and insert
77 // items in the correct order
78 m_strings
= new wxSortedArrayString
;
81 m_widget
= gtk_combo_box_new_text();
82 g_object_ref(m_widget
);
86 m_parent
->DoAddChild( this );
90 g_signal_connect_after (m_widget
, "changed",
91 G_CALLBACK (gtk_choice_changed_callback
), this);
101 void wxChoice::SendSelectionChangedEvent(wxEventType evt_type
)
106 if (GetSelection() == -1)
109 wxCommandEvent
event( evt_type
, GetId() );
111 int n
= GetSelection();
113 event
.SetString( GetStringSelection() );
114 event
.SetEventObject( this );
115 InitCommandEventWithItems( event
, n
);
117 HandleWindowEvent( event
);
120 void wxChoice::GTKInsertComboBoxTextItem( unsigned int n
, const wxString
& text
)
122 gtk_combo_box_insert_text( GTK_COMBO_BOX( m_widget
), n
, wxGTK_CONV( text
) );
125 int wxChoice::DoInsertItems(const wxArrayStringsAdapter
& items
,
127 void **clientData
, wxClientDataType type
)
129 wxCHECK_MSG( m_widget
!= NULL
, -1, wxT("invalid control") );
131 wxASSERT_MSG( !IsSorted() || (pos
== GetCount()),
132 _T("In a sorted choice data could only be appended"));
134 const int count
= items
.GetCount();
138 for ( int i
= 0; i
< count
; ++i
)
141 // If sorted, use this wxSortedArrayStrings to determine
142 // the right insertion point
144 n
= m_strings
->Add(items
[i
]);
146 GTKInsertComboBoxTextItem( n
, items
[i
] );
148 m_clientData
.Insert( NULL
, n
);
149 AssignNewItemClientData(n
, clientData
, i
, type
);
152 InvalidateBestSize();
157 void wxChoice::DoSetItemClientData(unsigned int n
, void* clientData
)
159 m_clientData
[n
] = clientData
;
162 void* wxChoice::DoGetItemClientData(unsigned int n
) const
164 return m_clientData
[n
];
167 void wxChoice::DoClear()
169 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid control") );
173 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
174 GtkTreeModel
* model
= gtk_combo_box_get_model( combobox
);
175 gtk_list_store_clear(GTK_LIST_STORE(model
));
177 m_clientData
.Clear();
184 InvalidateBestSize();
187 void wxChoice::DoDeleteOneItem(unsigned int n
)
189 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid control") );
190 wxCHECK_RET( IsValid(n
), _T("invalid index in wxChoice::Delete") );
192 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
193 GtkTreeModel
* model
= gtk_combo_box_get_model( combobox
);
194 GtkListStore
* store
= GTK_LIST_STORE(model
);
196 gtk_tree_model_iter_nth_child( model
, &iter
,
198 gtk_list_store_remove( store
, &iter
);
200 m_clientData
.RemoveAt( n
);
202 m_strings
->RemoveAt( n
);
204 InvalidateBestSize();
207 int wxChoice::FindString( const wxString
&item
, bool bCase
) const
209 wxCHECK_MSG( m_widget
!= NULL
, wxNOT_FOUND
, wxT("invalid control") );
211 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
212 GtkTreeModel
* model
= gtk_combo_box_get_model( combobox
);
214 gtk_tree_model_get_iter_first( model
, &iter
);
215 if (!gtk_list_store_iter_is_valid(GTK_LIST_STORE(model
), &iter
))
220 GValue value
= { 0, };
221 gtk_tree_model_get_value( model
, &iter
, m_stringCellIndex
, &value
);
222 wxString str
= wxGTK_CONV_BACK( g_value_get_string( &value
) );
223 g_value_unset( &value
);
225 if (item
.IsSameAs( str
, bCase
) )
230 while ( gtk_tree_model_iter_next(model
, &iter
) );
235 int wxChoice::GetSelection() const
237 return gtk_combo_box_get_active( GTK_COMBO_BOX( m_widget
) );
240 void wxChoice::SetString(unsigned int n
, const wxString
&text
)
242 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid control") );
244 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
245 wxCHECK_RET( IsValid(n
), wxT("invalid index") );
247 GtkTreeModel
*model
= gtk_combo_box_get_model( combobox
);
249 if (gtk_tree_model_iter_nth_child (model
, &iter
, NULL
, n
))
251 GValue value
= { 0, };
252 g_value_init( &value
, G_TYPE_STRING
);
253 g_value_set_string( &value
, wxGTK_CONV( text
) );
254 gtk_list_store_set_value( GTK_LIST_STORE(model
), &iter
, m_stringCellIndex
, &value
);
255 g_value_unset( &value
);
258 InvalidateBestSize();
261 wxString
wxChoice::GetString(unsigned int n
) const
263 wxCHECK_MSG( m_widget
!= NULL
, wxEmptyString
, wxT("invalid control") );
267 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
268 GtkTreeModel
*model
= gtk_combo_box_get_model( combobox
);
270 if (gtk_tree_model_iter_nth_child (model
, &iter
, NULL
, n
))
272 GValue value
= { 0, };
273 gtk_tree_model_get_value( model
, &iter
, m_stringCellIndex
, &value
);
274 wxString tmp
= wxGTK_CONV_BACK( g_value_get_string( &value
) );
275 g_value_unset( &value
);
282 unsigned int wxChoice::GetCount() const
284 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid control") );
286 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
287 GtkTreeModel
* model
= gtk_combo_box_get_model( combobox
);
289 gtk_tree_model_get_iter_first( model
, &iter
);
290 if (!gtk_list_store_iter_is_valid(GTK_LIST_STORE(model
), &iter
))
292 unsigned int ret
= 1;
293 while (gtk_tree_model_iter_next( model
, &iter
))
298 void wxChoice::SetSelection( int n
)
300 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid control") );
304 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
305 gtk_combo_box_set_active( combobox
, n
);
310 void wxChoice::SetColumns(int n
)
312 gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(m_widget
), n
);
315 int wxChoice::GetColumns() const
317 // gtk_combo_box_get_wrap_width() was added in gtk 2.6
319 g_object_get(G_OBJECT(m_widget
), "wrap-width", &intval
, NULL
);
324 void wxChoice::DisableEvents()
326 g_signal_handlers_block_by_func(m_widget
,
327 (gpointer
) gtk_choice_changed_callback
, this);
330 void wxChoice::EnableEvents()
332 g_signal_handlers_unblock_by_func(m_widget
,
333 (gpointer
) gtk_choice_changed_callback
, this);
337 GdkWindow
*wxChoice::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
339 return m_widget
->window
;
342 // Notice that this method shouldn't be necessary, because GTK calculates
343 // properly size of the combobox but for unknown reasons it doesn't work
344 // correctly in wx without this.
345 wxSize
wxChoice::DoGetBestSize() const
347 // strangely, this returns a width of 188 pixels from GTK+ (?)
348 wxSize
ret( wxControl::DoGetBestSize() );
350 // we know better our horizontal extent: it depends on the longest string
354 ret
.x
= GetCount() > 0 ? 0 : 60; // start with something "sensible"
356 unsigned int count
= GetCount();
357 for ( unsigned int n
= 0; n
< count
; n
++ )
359 GetTextExtent(GetString(n
), &width
, NULL
, NULL
, NULL
);
360 if ( width
+ 40 > ret
.x
) // 40 for drop down arrow and space around text
365 // empty combobox should have some reasonable default size too
366 if ((GetCount() == 0) && (ret
.x
< 80))
373 void wxChoice::DoApplyWidgetStyle(GtkRcStyle
*style
)
375 gtk_widget_modify_style(m_widget
, style
);
376 gtk_widget_modify_style(GTK_BIN(m_widget
)->child
, style
);
382 wxChoice::GetClassDefaultAttributes(wxWindowVariant
WXUNUSED(variant
))
384 return GetDefaultAttributesFromGTKWidget(gtk_combo_box_new
);
388 #endif // wxUSE_CHOICE || wxUSE_COMBOBOX