1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/choice.cpp
4 // Author: Robert Roebling
5 // Copyright: (c) 1998 Robert Roebling
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
11 #if wxUSE_CHOICE || wxUSE_COMBOBOX
13 #include "wx/choice.h"
16 #include "wx/arrstr.h"
20 #include "wx/gtk/private.h"
21 #include "wx/gtk/private/gtk2-compat.h"
23 // ----------------------------------------------------------------------------
25 // ----------------------------------------------------------------------------
30 gtk_choice_changed_callback( GtkWidget
*WXUNUSED(widget
), wxChoice
*choice
)
32 choice
->SendSelectionChangedEvent(wxEVT_CHOICE
);
37 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
44 m_stringCellIndex
= 0;
47 bool wxChoice::Create( wxWindow
*parent
, wxWindowID id
,
48 const wxPoint
&pos
, const wxSize
&size
,
49 const wxArrayString
& choices
,
50 long style
, const wxValidator
& validator
,
51 const wxString
&name
)
53 wxCArrayString
chs(choices
);
55 return Create( parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(),
56 style
, validator
, name
);
59 bool wxChoice::Create( wxWindow
*parent
, wxWindowID id
,
60 const wxPoint
&pos
, const wxSize
&size
,
61 int n
, const wxString choices
[],
62 long style
, const wxValidator
& validator
,
63 const wxString
&name
)
65 if (!PreCreation( parent
, pos
, size
) ||
66 !CreateBase( parent
, id
, pos
, size
, style
, validator
, name
))
68 wxFAIL_MSG( wxT("wxChoice creation failed") );
74 // if our m_strings != NULL, Append() will check for it and insert
75 // items in the correct order
76 m_strings
= new wxGtkCollatedArrayString
;
80 m_widget
= gtk_combo_box_text_new();
82 m_widget
= gtk_combo_box_new_text();
84 g_object_ref(m_widget
);
88 m_parent
->DoAddChild( this );
92 g_signal_connect_after (m_widget
, "changed",
93 G_CALLBACK (gtk_choice_changed_callback
), this);
103 void wxChoice::GTKInsertComboBoxTextItem( unsigned int n
, const wxString
& text
)
106 gtk_combo_box_text_insert_text(GTK_COMBO_BOX_TEXT(m_widget
), n
, wxGTK_CONV(text
));
108 gtk_combo_box_insert_text( GTK_COMBO_BOX( m_widget
), n
, wxGTK_CONV( text
) );
112 int wxChoice::DoInsertItems(const wxArrayStringsAdapter
& items
,
114 void **clientData
, wxClientDataType type
)
116 wxCHECK_MSG( m_widget
!= NULL
, -1, wxT("invalid control") );
118 wxASSERT_MSG( !IsSorted() || (pos
== GetCount()),
119 wxT("In a sorted choice data could only be appended"));
121 const int count
= items
.GetCount();
125 for ( int i
= 0; i
< count
; ++i
)
128 // If sorted, use this wxSortedArrayStrings to determine
129 // the right insertion point
131 n
= m_strings
->Add(items
[i
]);
133 GTKInsertComboBoxTextItem( n
, items
[i
] );
135 m_clientData
.Insert( NULL
, n
);
136 AssignNewItemClientData(n
, clientData
, i
, type
);
139 InvalidateBestSize();
144 void wxChoice::DoSetItemClientData(unsigned int n
, void* clientData
)
146 m_clientData
[n
] = clientData
;
149 void* wxChoice::DoGetItemClientData(unsigned int n
) const
151 return m_clientData
[n
];
154 void wxChoice::DoClear()
156 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid control") );
160 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
161 GtkTreeModel
* model
= gtk_combo_box_get_model( combobox
);
162 gtk_list_store_clear(GTK_LIST_STORE(model
));
164 m_clientData
.Clear();
171 InvalidateBestSize();
174 void wxChoice::DoDeleteOneItem(unsigned int n
)
176 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid control") );
177 wxCHECK_RET( IsValid(n
), wxT("invalid index in wxChoice::Delete") );
179 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
180 GtkTreeModel
* model
= gtk_combo_box_get_model( combobox
);
181 GtkListStore
* store
= GTK_LIST_STORE(model
);
183 if ( !gtk_tree_model_iter_nth_child(model
, &iter
, NULL
, n
) )
185 // This is really not supposed to happen for a valid index.
186 wxFAIL_MSG(wxS("Item unexpectedly not found."));
189 gtk_list_store_remove( store
, &iter
);
191 m_clientData
.RemoveAt( n
);
193 m_strings
->RemoveAt( n
);
195 InvalidateBestSize();
198 int wxChoice::FindString( const wxString
&item
, bool bCase
) const
200 wxCHECK_MSG( m_widget
!= NULL
, wxNOT_FOUND
, wxT("invalid control") );
202 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
203 GtkTreeModel
* model
= gtk_combo_box_get_model( combobox
);
205 gtk_tree_model_get_iter_first( model
, &iter
);
206 if (!gtk_list_store_iter_is_valid(GTK_LIST_STORE(model
), &iter
))
211 GValue value
= { 0, };
212 gtk_tree_model_get_value( model
, &iter
, m_stringCellIndex
, &value
);
213 wxString str
= wxGTK_CONV_BACK( g_value_get_string( &value
) );
214 g_value_unset( &value
);
216 if (item
.IsSameAs( str
, bCase
) )
221 while ( gtk_tree_model_iter_next(model
, &iter
) );
226 int wxChoice::GetSelection() const
228 return gtk_combo_box_get_active( GTK_COMBO_BOX( m_widget
) );
231 void wxChoice::SetString(unsigned int n
, const wxString
&text
)
233 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid control") );
235 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
236 wxCHECK_RET( IsValid(n
), wxT("invalid index") );
238 GtkTreeModel
*model
= gtk_combo_box_get_model( combobox
);
240 if (gtk_tree_model_iter_nth_child (model
, &iter
, NULL
, n
))
242 GValue value
= { 0, };
243 g_value_init( &value
, G_TYPE_STRING
);
244 g_value_set_string( &value
, wxGTK_CONV( text
) );
245 gtk_list_store_set_value( GTK_LIST_STORE(model
), &iter
, m_stringCellIndex
, &value
);
246 g_value_unset( &value
);
249 InvalidateBestSize();
252 wxString
wxChoice::GetString(unsigned int n
) const
254 wxCHECK_MSG( m_widget
!= NULL
, wxEmptyString
, wxT("invalid control") );
258 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
259 GtkTreeModel
*model
= gtk_combo_box_get_model( combobox
);
261 if (gtk_tree_model_iter_nth_child (model
, &iter
, NULL
, n
))
263 GValue value
= { 0, };
264 gtk_tree_model_get_value( model
, &iter
, m_stringCellIndex
, &value
);
265 wxString tmp
= wxGTK_CONV_BACK( g_value_get_string( &value
) );
266 g_value_unset( &value
);
273 unsigned int wxChoice::GetCount() const
275 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid control") );
277 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
278 GtkTreeModel
* model
= gtk_combo_box_get_model( combobox
);
280 gtk_tree_model_get_iter_first( model
, &iter
);
281 if (!gtk_list_store_iter_is_valid(GTK_LIST_STORE(model
), &iter
))
283 unsigned int ret
= 1;
284 while (gtk_tree_model_iter_next( model
, &iter
))
289 void wxChoice::SetSelection( int n
)
291 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid control") );
295 GtkComboBox
* combobox
= GTK_COMBO_BOX( m_widget
);
296 gtk_combo_box_set_active( combobox
, n
);
301 void wxChoice::SetColumns(int n
)
303 gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(m_widget
), n
);
306 int wxChoice::GetColumns() const
308 // gtk_combo_box_get_wrap_width() was added in gtk 2.6
310 g_object_get(G_OBJECT(m_widget
), "wrap-width", &intval
, NULL
);
314 void wxChoice::GTKDisableEvents()
316 g_signal_handlers_block_by_func(m_widget
,
317 (gpointer
) gtk_choice_changed_callback
, this);
320 void wxChoice::GTKEnableEvents()
322 g_signal_handlers_unblock_by_func(m_widget
,
323 (gpointer
) gtk_choice_changed_callback
, this);
326 GdkWindow
*wxChoice::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
328 return gtk_widget_get_window(m_widget
);
331 wxSize
wxChoice::DoGetBestSize() const
333 // Get the height of the control from GTK+ itself, but use our own version
334 // to compute the width large enough to show all our strings as GTK+
335 // doesn't seem to take the control contents into account.
336 return GetSizeFromTextSize(wxChoiceBase::DoGetBestSize().x
);
339 wxSize
wxChoice::DoGetSizeFromTextSize(int xlen
, int ylen
) const
341 wxASSERT_MSG( m_widget
, wxS("GetSizeFromTextSize called before creation") );
343 // a GtkEntry for wxComboBox and a GtkCellView for wxChoice
344 GtkWidget
* childPart
= gtk_bin_get_child(GTK_BIN(m_widget
));
346 // Set a as small as possible size for the control, so preferred sizes
347 // return "natural" sizes, not taking into account the previous ones (which
348 // seems to be GTK+3 behaviour)
349 gtk_widget_set_size_request(m_widget
, 0, 0);
351 // We are interested in the difference of sizes between the whole contol
352 // and its child part. I.e. arrow, separators, etc.
354 gtk_widget_get_preferred_size(childPart
, NULL
, &req
);
355 wxSize totalS
= GTKGetPreferredSize(m_widget
);
357 wxSize
tsize(xlen
+ totalS
.x
- req
.width
, totalS
.y
);
359 // For a wxChoice, not for wxComboBox, add some margins
360 if ( !GTK_IS_ENTRY(childPart
) )
363 // Perhaps the user wants something different from CharHeight
365 tsize
.IncBy(0, ylen
- GetCharHeight());
370 void wxChoice::DoApplyWidgetStyle(GtkRcStyle
*style
)
372 GTKApplyStyle(m_widget
, style
);
373 GTKApplyStyle(gtk_bin_get_child(GTK_BIN(m_widget
)), style
);
378 wxChoice::GetClassDefaultAttributes(wxWindowVariant
WXUNUSED(variant
))
380 return GetDefaultAttributesFromGTKWidget(gtk_combo_box_new());
383 #endif // wxUSE_CHOICE || wxUSE_COMBOBOX