]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/choice.cpp
Added wxRichTextTableBlock class to help with table UI operations
[wxWidgets.git] / src / gtk / choice.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
11e62fe6 2// Name: src/gtk/choice.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
01111366 5// Copyright: (c) 1998 Robert Roebling
65571936 6// Licence: wxWindows licence
c801d85f
KB
7/////////////////////////////////////////////////////////////////////////////
8
8228b893 9#include "wx/wxprec.h"
c801d85f 10
a2c94110 11#if wxUSE_CHOICE || wxUSE_COMBOBOX
ce4169a4 12
1e6feb95 13#include "wx/choice.h"
aaa6d89a
WS
14
15#ifndef WX_PRECOMP
16 #include "wx/arrstr.h"
17#endif
1e6feb95 18
9dc44eff 19#include <gtk/gtk.h>
9e691f46 20#include "wx/gtk/private.h"
9dc44eff 21#include "wx/gtk/private/gtk2-compat.h"
66bd6b93 22
a2c94110
VZ
23// ----------------------------------------------------------------------------
24// GTK callbacks
25// ----------------------------------------------------------------------------
c801d85f 26
865bb325 27extern "C" {
6c8a980f 28
a2c94110
VZ
29static void
30gtk_choice_changed_callback( GtkWidget *WXUNUSED(widget), wxChoice *choice )
31{
ce7fe42e 32 choice->SendSelectionChangedEvent(wxEVT_CHOICE);
6de97a3b 33}
a2c94110 34
865bb325 35}
c801d85f 36
e1e955e1
RR
37//-----------------------------------------------------------------------------
38// wxChoice
c801d85f
KB
39//-----------------------------------------------------------------------------
40
e78c1d78 41void wxChoice::Init()
c801d85f 42{
d3b9f782 43 m_strings = NULL;
e78c1d78 44 m_stringCellIndex = 0;
6de97a3b 45}
c801d85f 46
584ad2a3
MB
47bool 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 )
52{
53 wxCArrayString chs(choices);
54
55 return Create( parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
56 style, validator, name );
57}
58
debe6624 59bool wxChoice::Create( wxWindow *parent, wxWindowID id,
fd0eed64
RR
60 const wxPoint &pos, const wxSize &size,
61 int n, const wxString choices[],
a2c94110
VZ
62 long style, const wxValidator& validator,
63 const wxString &name )
c801d85f 64{
4dcaf11a
RR
65 if (!PreCreation( parent, pos, size ) ||
66 !CreateBase( parent, id, pos, size, style, validator, name ))
67 {
223d09f6 68 wxFAIL_MSG( wxT("wxChoice creation failed") );
0a164d4c 69 return false;
4dcaf11a 70 }
6de97a3b 71
a236aa20 72 if ( IsSorted() )
e01c8145 73 {
a236aa20 74 // if our m_strings != NULL, Append() will check for it and insert
e01c8145 75 // items in the correct order
c272f12f 76 m_strings = new wxGtkCollatedArrayString;
e01c8145
VZ
77 }
78
9dc44eff
PC
79#ifdef __WXGTK3__
80 m_widget = gtk_combo_box_text_new();
81#else
a2c94110 82 m_widget = gtk_combo_box_new_text();
9dc44eff 83#endif
9ff9d30c 84 g_object_ref(m_widget);
16edee16 85
a2c94110 86 Append(n, choices);
29006414 87
f03fc89f 88 m_parent->DoAddChild( this );
29006414 89
abdeb9e7 90 PostCreation(size);
29006414 91
a2c94110
VZ
92 g_signal_connect_after (m_widget, "changed",
93 G_CALLBACK (gtk_choice_changed_callback), this);
4b8e857f 94
0a164d4c 95 return true;
6de97a3b 96}
29006414 97
fd0eed64
RR
98wxChoice::~wxChoice()
99{
e01c8145 100 delete m_strings;
fd0eed64
RR
101}
102
e78c1d78
RR
103void wxChoice::GTKInsertComboBoxTextItem( unsigned int n, const wxString& text )
104{
9dc44eff
PC
105#ifdef __WXGTK3__
106 gtk_combo_box_text_insert_text(GTK_COMBO_BOX_TEXT(m_widget), n, wxGTK_CONV(text));
107#else
e78c1d78 108 gtk_combo_box_insert_text( GTK_COMBO_BOX( m_widget ), n, wxGTK_CONV( text ) );
9dc44eff 109#endif
e78c1d78
RR
110}
111
a236aa20
VZ
112int wxChoice::DoInsertItems(const wxArrayStringsAdapter & items,
113 unsigned int pos,
114 void **clientData, wxClientDataType type)
fd0eed64 115{
a2c94110 116 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid control") );
29006414 117
a2c94110 118 wxASSERT_MSG( !IsSorted() || (pos == GetCount()),
9a83f860 119 wxT("In a sorted choice data could only be appended"));
243dbf1a 120
a2c94110 121 const int count = items.GetCount();
243dbf1a 122
a2c94110
VZ
123 int n = wxNOT_FOUND;
124
a2c94110 125 for ( int i = 0; i < count; ++i )
a236aa20 126 {
a2c94110
VZ
127 n = pos + i;
128 // If sorted, use this wxSortedArrayStrings to determine
129 // the right insertion point
c272f12f 130 if (m_strings)
a2c94110 131 n = m_strings->Add(items[i]);
ce00f59b 132
e78c1d78 133 GTKInsertComboBoxTextItem( n, items[i] );
243dbf1a 134
a2c94110
VZ
135 m_clientData.Insert( NULL, n );
136 AssignNewItemClientData(n, clientData, i, type);
16edee16
RR
137 }
138
a2c94110 139 InvalidateBestSize();
261a9107 140
a2c94110 141 return n;
fd0eed64 142}
f96aa4d9 143
aa61d352 144void wxChoice::DoSetItemClientData(unsigned int n, void* clientData)
fd0eed64 145{
a236aa20 146 m_clientData[n] = clientData;
fd0eed64
RR
147}
148
aa61d352 149void* wxChoice::DoGetItemClientData(unsigned int n) const
fd0eed64 150{
a236aa20 151 return m_clientData[n];
fd0eed64 152}
29006414 153
a236aa20 154void wxChoice::DoClear()
c801d85f 155{
a2c94110 156 wxCHECK_RET( m_widget != NULL, wxT("invalid control") );
f96aa4d9 157
bce926c5 158 GTKDisableEvents();
a2c94110 159
e78c1d78
RR
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));
29006414 163
a236aa20 164 m_clientData.Clear();
2ee3ee1b 165
a2c94110 166 if (m_strings)
2ee3ee1b 167 m_strings->Clear();
16edee16 168
bce926c5 169 GTKEnableEvents();
a2c94110
VZ
170
171 InvalidateBestSize();
6de97a3b 172}
c801d85f 173
a236aa20 174void wxChoice::DoDeleteOneItem(unsigned int n)
2f6407b9 175{
a2c94110 176 wxCHECK_RET( m_widget != NULL, wxT("invalid control") );
9a83f860 177 wxCHECK_RET( IsValid(n), wxT("invalid index in wxChoice::Delete") );
645420d8 178
e78c1d78
RR
179 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
180 GtkTreeModel* model = gtk_combo_box_get_model( combobox );
181 GtkListStore* store = GTK_LIST_STORE(model);
182 GtkTreeIter iter;
bcfe86f0
VZ
183 if ( !gtk_tree_model_iter_nth_child(model, &iter, NULL, n) )
184 {
185 // This is really not supposed to happen for a valid index.
186 wxFAIL_MSG(wxS("Item unexpectedly not found."));
187 return;
188 }
e78c1d78
RR
189 gtk_list_store_remove( store, &iter );
190
a2c94110
VZ
191 m_clientData.RemoveAt( n );
192 if ( m_strings )
193 m_strings->RemoveAt( n );
e2380ce1 194
a2c94110 195 InvalidateBestSize();
2f6407b9
RR
196}
197
a2c94110 198int wxChoice::FindString( const wxString &item, bool bCase ) const
c801d85f 199{
a2c94110
VZ
200 wxCHECK_MSG( m_widget != NULL, wxNOT_FOUND, wxT("invalid control") );
201
202 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
203 GtkTreeModel* model = gtk_combo_box_get_model( combobox );
204 GtkTreeIter iter;
205 gtk_tree_model_get_iter_first( model, &iter );
206 if (!gtk_list_store_iter_is_valid(GTK_LIST_STORE(model), &iter ))
207 return -1;
fd0eed64 208 int count = 0;
a2c94110 209 do
fd0eed64 210 {
a2c94110 211 GValue value = { 0, };
e78c1d78 212 gtk_tree_model_get_value( model, &iter, m_stringCellIndex, &value );
a2c94110
VZ
213 wxString str = wxGTK_CONV_BACK( g_value_get_string( &value ) );
214 g_value_unset( &value );
29006414 215
a2c94110 216 if (item.IsSameAs( str, bCase ) )
9e691f46 217 return count;
29006414 218
9e691f46 219 count++;
fd0eed64 220 }
a2c94110 221 while ( gtk_tree_model_iter_next(model, &iter) );
29006414 222
0a164d4c 223 return wxNOT_FOUND;
6de97a3b 224}
c801d85f 225
9abe166a 226int wxChoice::GetSelection() const
c801d85f 227{
a2c94110 228 return gtk_combo_box_get_active( GTK_COMBO_BOX( m_widget ) );
6de97a3b 229}
c801d85f 230
a2c94110 231void wxChoice::SetString(unsigned int n, const wxString &text)
6c8a980f 232{
a2c94110
VZ
233 wxCHECK_RET( m_widget != NULL, wxT("invalid control") );
234
235 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
236 wxCHECK_RET( IsValid(n), wxT("invalid index") );
6c8a980f 237
a2c94110
VZ
238 GtkTreeModel *model = gtk_combo_box_get_model( combobox );
239 GtkTreeIter iter;
240 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, n))
34b5e560 241 {
a2c94110
VZ
242 GValue value = { 0, };
243 g_value_init( &value, G_TYPE_STRING );
244 g_value_set_string( &value, wxGTK_CONV( text ) );
e78c1d78 245 gtk_list_store_set_value( GTK_LIST_STORE(model), &iter, m_stringCellIndex, &value );
a2c94110 246 g_value_unset( &value );
34b5e560 247 }
a2c94110
VZ
248
249 InvalidateBestSize();
6c8a980f
VZ
250}
251
aa61d352 252wxString wxChoice::GetString(unsigned int n) const
c801d85f 253{
a2c94110
VZ
254 wxCHECK_MSG( m_widget != NULL, wxEmptyString, wxT("invalid control") );
255
256 wxString str;
fd0eed64 257
a2c94110
VZ
258 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
259 GtkTreeModel *model = gtk_combo_box_get_model( combobox );
260 GtkTreeIter iter;
261 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, n))
c801d85f 262 {
a2c94110 263 GValue value = { 0, };
e78c1d78 264 gtk_tree_model_get_value( model, &iter, m_stringCellIndex, &value );
a2c94110
VZ
265 wxString tmp = wxGTK_CONV_BACK( g_value_get_string( &value ) );
266 g_value_unset( &value );
267 return tmp;
6de97a3b 268 }
29006414 269
a2c94110 270 return str;
6de97a3b 271}
c801d85f 272
aa61d352 273unsigned int wxChoice::GetCount() const
c801d85f 274{
a2c94110
VZ
275 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid control") );
276
277 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
278 GtkTreeModel* model = gtk_combo_box_get_model( combobox );
279 GtkTreeIter iter;
280 gtk_tree_model_get_iter_first( model, &iter );
281 if (!gtk_list_store_iter_is_valid(GTK_LIST_STORE(model), &iter ))
282 return 0;
283 unsigned int ret = 1;
284 while (gtk_tree_model_iter_next( model, &iter ))
285 ret++;
286 return ret;
6de97a3b 287}
c801d85f 288
debe6624 289void wxChoice::SetSelection( int n )
c801d85f 290{
a2c94110 291 wxCHECK_RET( m_widget != NULL, wxT("invalid control") );
29006414 292
bce926c5 293 GTKDisableEvents();
29006414 294
a2c94110
VZ
295 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
296 gtk_combo_box_set_active( combobox, n );
29006414 297
bce926c5 298 GTKEnableEvents();
f96aa4d9
RR
299}
300
3f16e52c
RR
301void wxChoice::SetColumns(int n)
302{
303 gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(m_widget), n);
304}
305
306int wxChoice::GetColumns() const
307{
308 // gtk_combo_box_get_wrap_width() was added in gtk 2.6
309 gint intval;
310 g_object_get(G_OBJECT(m_widget), "wrap-width", &intval, NULL);
311 return intval;
312}
313
bce926c5 314void wxChoice::GTKDisableEvents()
e01c8145 315{
a2c94110
VZ
316 g_signal_handlers_block_by_func(m_widget,
317 (gpointer) gtk_choice_changed_callback, this);
e01c8145
VZ
318}
319
bce926c5 320void wxChoice::GTKEnableEvents()
f68586e5 321{
a2c94110
VZ
322 g_signal_handlers_unblock_by_func(m_widget,
323 (gpointer) gtk_choice_changed_callback, this);
f68586e5
VZ
324}
325
ef5c70f9 326GdkWindow *wxChoice::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
2b904684 327{
385e8575 328 return gtk_widget_get_window(m_widget);
2b904684
RR
329}
330
0662f990
VZ
331wxSize wxChoice::DoGetBestSize() const
332{
7eb0acef
VZ
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.
7a78a937
VZ
336 return GetSizeFromTextSize(wxChoiceBase::DoGetBestSize().x);
337}
338
339wxSize wxChoice::DoGetSizeFromTextSize(int xlen, int ylen) const
340{
341 wxASSERT_MSG( m_widget, wxS("GetSizeFromTextSize called before creation") );
342
343 // a GtkEntry for wxComboBox and a GtkCellView for wxChoice
344 GtkWidget* childPart = gtk_bin_get_child(GTK_BIN(m_widget));
345
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);
350
351 // We are interested in the difference of sizes between the whole contol
352 // and its child part. I.e. arrow, separators, etc.
353 GtkRequisition req;
1897abe1 354 gtk_widget_get_preferred_size(childPart, NULL, &req);
7a78a937
VZ
355 wxSize totalS = GTKGetPreferredSize(m_widget);
356
357 wxSize tsize(xlen + totalS.x - req.width, totalS.y);
358
359 // For a wxChoice, not for wxComboBox, add some margins
360 if ( !GTK_IS_ENTRY(childPart) )
361 tsize.IncBy(5, 0);
362
363 // Perhaps the user wants something different from CharHeight
364 if ( ylen > 0 )
365 tsize.IncBy(0, ylen - GetCharHeight());
366
367 return tsize;
0662f990
VZ
368}
369
c2193ac9
RR
370void wxChoice::DoApplyWidgetStyle(GtkRcStyle *style)
371{
9dc44eff
PC
372 GTKApplyStyle(m_widget, style);
373 GTKApplyStyle(gtk_bin_get_child(GTK_BIN(m_widget)), style);
c2193ac9
RR
374}
375
9d522606
RD
376// static
377wxVisualAttributes
378wxChoice::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
379{
7fff16b8 380 return GetDefaultAttributesFromGTKWidget(gtk_combo_box_new());
9d522606
RD
381}
382
a2c94110 383#endif // wxUSE_CHOICE || wxUSE_COMBOBOX