]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/combobox.cpp
implementation streamlined
[wxWidgets.git] / src / gtk / combobox.cpp
CommitLineData
53010e52 1/////////////////////////////////////////////////////////////////////////////
11e62fe6 2// Name: src/gtk/combobox.cpp
53010e52
RR
3// Purpose:
4// Author: Robert Roebling
dbf858b5 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
53010e52
RR
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
dcf924a3
RR
13#if wxUSE_COMBOBOX
14
8228b893
WS
15#include "wx/combobox.h"
16
72a16063 17#include "wx/settings.h"
584ad2a3 18#include "wx/arrstr.h"
b62c3631 19#include "wx/intl.h"
53010e52 20
78bcfcfc
VZ
21#include "wx/textctrl.h" // for wxEVT_COMMAND_TEXT_UPDATED
22
1efb5db8
MR
23// We use GtkCombo which has been deprecated since GTK+ 2.3.0
24// in favour of GtkComboBox for <GTK2.4 runtime
5b008dd7
MR
25// We also use GtkList
26#ifdef GTK_DISABLE_DEPRECATED
1efb5db8
MR
27#undef GTK_DISABLE_DEPRECATED
28#endif
9e691f46 29#include "wx/gtk/private.h"
83624f79 30
47908e25
RR
31//-----------------------------------------------------------------------------
32// data
33//-----------------------------------------------------------------------------
34
35extern bool g_blockEventsOnDrag;
40eb3606
VZ
36static int g_SelectionBeforePopup = wxID_NONE; // this means the popup is hidden
37
78b3b018
RR
38//-----------------------------------------------------------------------------
39// "changed" - typing and list item matches get changed, select-child
40// if it doesn't match an item then just get a single changed
41//-----------------------------------------------------------------------------
42
865bb325 43extern "C" {
78b3b018 44static void
1fb33bdb 45gtkcombo_text_changed_callback( GtkWidget *WXUNUSED(widget), wxComboBox *combo )
78b3b018
RR
46{
47 if (g_isIdle) wxapp_install_idle_handler();
48
49 if (combo->m_ignoreNextUpdate)
150e31d2 50 {
7d8268a1 51 combo->m_ignoreNextUpdate = false;
78b3b018
RR
52 return;
53 }
54
55 if (!combo->m_hasVMT) return;
56
57 wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, combo->GetId() );
58 event.SetString( combo->GetValue() );
59 event.SetEventObject( combo );
60 combo->GetEventHandler()->ProcessEvent( event );
61}
865bb325 62}
78b3b018 63
865bb325 64extern "C" {
78b3b018 65static void
1fb33bdb 66gtkcombo_dummy_callback(GtkEntry *WXUNUSED(entry), GtkCombo *WXUNUSED(combo))
78b3b018
RR
67{
68}
865bb325 69}
78b3b018 70
865bb325 71extern "C" {
9d6a9fdd 72static void
1fb33bdb 73gtkcombo_popup_hide_callback(GtkCombo *WXUNUSED(gtk_combo), wxComboBox *combo)
7d8268a1 74{
9d6a9fdd
RR
75 // when the popup is hidden, throw a SELECTED event only if the combobox
76 // selection changed.
3dbfe8f4
VZ
77 const int curSelection = combo->GetCurrentSelection();
78
79 const bool hasChanged = curSelection != g_SelectionBeforePopup;
80
81 // reset the selection flag to value meaning that it is hidden and do it
82 // now, before generating the events, so that GetSelection() returns the
83 // new value from the event handler
84 g_SelectionBeforePopup = wxID_NONE;
85
86 if ( hasChanged )
9d6a9fdd
RR
87 {
88 wxCommandEvent event( wxEVT_COMMAND_COMBOBOX_SELECTED, combo->GetId() );
89 event.SetInt( curSelection );
90 event.SetString( combo->GetStringSelection() );
91 event.SetEventObject( combo );
92 combo->GetEventHandler()->ProcessEvent( event );
345bdf13
KH
93
94 // for consistency with the other ports, send TEXT event
95 wxCommandEvent event2( wxEVT_COMMAND_TEXT_UPDATED, combo->GetId() );
96 event2.SetString( combo->GetStringSelection() );
97 event2.SetEventObject( combo );
98 combo->GetEventHandler()->ProcessEvent( event2 );
9d6a9fdd 99 }
9d6a9fdd 100}
865bb325 101}
9d6a9fdd 102
865bb325 103extern "C" {
9d6a9fdd 104static void
1fb33bdb 105gtkcombo_popup_show_callback(GtkCombo *WXUNUSED(gtk_combo), wxComboBox *combo)
9d6a9fdd
RR
106{
107 // store the combobox selection value before the popup is shown
40eb3606 108 g_SelectionBeforePopup = combo->GetCurrentSelection();
9d6a9fdd 109}
865bb325 110}
9d6a9fdd 111
53010e52 112//-----------------------------------------------------------------------------
461573cc 113// "select-child" - click/cursor get select-child, changed, select-child
47908e25 114//-----------------------------------------------------------------------------
47908e25 115
865bb325 116extern "C" {
8a85884a 117static void
1fb33bdb 118gtkcombo_combo_select_child_callback( GtkList *WXUNUSED(list), GtkWidget *WXUNUSED(widget), wxComboBox *combo )
53010e52 119{
acfd422a 120 if (g_isIdle) wxapp_install_idle_handler();
8a85884a 121
a2053b27 122 if (!combo->m_hasVMT) return;
30ed6e5c 123
acfd422a 124 if (g_blockEventsOnDrag) return;
805dd538 125
40eb3606 126 int curSelection = combo->GetCurrentSelection();
30ed6e5c 127
3c4e4af6
RR
128 if (combo->m_prevSelection == curSelection) return;
129
130 GtkWidget *list = GTK_COMBO(combo->m_widget)->list;
131 gtk_list_unselect_item( GTK_LIST(list), combo->m_prevSelection );
150e31d2 132
159b66c0
RR
133 combo->m_prevSelection = curSelection;
134
78b3b018
RR
135 // Quickly set the value of the combo box
136 // as GTK+ does that only AFTER the event
137 // is sent.
9fa72bd2 138 g_signal_handlers_disconnect_by_func (GTK_COMBO (combo->GetHandle())->entry,
1fb33bdb 139 (gpointer) gtkcombo_text_changed_callback,
9fa72bd2 140 combo);
78b3b018 141 combo->SetValue( combo->GetStringSelection() );
9fa72bd2 142 g_signal_connect_after (GTK_COMBO (combo->GetHandle())->entry, "changed",
1fb33bdb 143 G_CALLBACK (gtkcombo_text_changed_callback), combo);
78b3b018 144
40eb3606 145 // throw a SELECTED event only if the combobox popup is hidden (wxID_NONE)
1fb33bdb 146 // because when combobox popup is shown, gtkcombo_combo_select_child_callback is
9d6a9fdd
RR
147 // called each times the mouse is over an item with a pressed button so a lot
148 // of SELECTED event could be generated if the user keep the mouse button down
149 // and select other items ...
40eb3606 150 if (g_SelectionBeforePopup == wxID_NONE)
9d6a9fdd
RR
151 {
152 wxCommandEvent event( wxEVT_COMMAND_COMBOBOX_SELECTED, combo->GetId() );
153 event.SetInt( curSelection );
154 event.SetString( combo->GetStringSelection() );
155 event.SetEventObject( combo );
156 combo->GetEventHandler()->ProcessEvent( event );
0c77152e 157
345bdf13 158 // for consistency with the other ports, don't generate text update
40eb3606
VZ
159 // events while the user is browsing the combobox neither
160 wxCommandEvent event2( wxEVT_COMMAND_TEXT_UPDATED, combo->GetId() );
161 event2.SetString( combo->GetValue() );
162 event2.SetEventObject( combo );
163 combo->GetEventHandler()->ProcessEvent( event2 );
164 }
461573cc 165}
865bb325 166}
461573cc 167
590f50d6
RR
168#ifdef __WXGTK24__
169extern "C" {
170static void
171gtkcombobox_text_changed_callback( GtkWidget *WXUNUSED(widget), wxComboBox *combo )
172{
173 if (g_isIdle) wxapp_install_idle_handler();
174
175 if (!combo->m_hasVMT) return;
176
177 wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, combo->GetId() );
178 event.SetString( combo->GetValue() );
179 event.SetEventObject( combo );
180 combo->GetEventHandler()->ProcessEvent( event );
181}
182}
183
184extern "C" {
185static void
186gtkcombobox_changed_callback( GtkWidget *WXUNUSED(widget), wxComboBox *combo )
187{
188 if (g_isIdle) wxapp_install_idle_handler();
189
190 if (!combo->m_hasVMT) return;
191
192 wxCommandEvent event( wxEVT_COMMAND_COMBOBOX_SELECTED, combo->GetId() );
193 event.SetInt( combo->GetSelection() );
194 event.SetString( combo->GetStringSelection() );
195 event.SetEventObject( combo );
196 combo->GetEventHandler()->ProcessEvent( event );
197}
198}
199#endif
200
e1e955e1
RR
201//-----------------------------------------------------------------------------
202// wxComboBox
53010e52
RR
203//-----------------------------------------------------------------------------
204
205IMPLEMENT_DYNAMIC_CLASS(wxComboBox,wxControl)
206
b4071e91 207BEGIN_EVENT_TABLE(wxComboBox, wxControl)
fd0eed64 208 EVT_SIZE(wxComboBox::OnSize)
8a85884a 209 EVT_CHAR(wxComboBox::OnChar)
150e31d2
JS
210
211 EVT_MENU(wxID_CUT, wxComboBox::OnCut)
212 EVT_MENU(wxID_COPY, wxComboBox::OnCopy)
213 EVT_MENU(wxID_PASTE, wxComboBox::OnPaste)
214 EVT_MENU(wxID_UNDO, wxComboBox::OnUndo)
215 EVT_MENU(wxID_REDO, wxComboBox::OnRedo)
216 EVT_MENU(wxID_CLEAR, wxComboBox::OnDelete)
217 EVT_MENU(wxID_SELECTALL, wxComboBox::OnSelectAll)
218
219 EVT_UPDATE_UI(wxID_CUT, wxComboBox::OnUpdateCut)
220 EVT_UPDATE_UI(wxID_COPY, wxComboBox::OnUpdateCopy)
221 EVT_UPDATE_UI(wxID_PASTE, wxComboBox::OnUpdatePaste)
222 EVT_UPDATE_UI(wxID_UNDO, wxComboBox::OnUpdateUndo)
223 EVT_UPDATE_UI(wxID_REDO, wxComboBox::OnUpdateRedo)
224 EVT_UPDATE_UI(wxID_CLEAR, wxComboBox::OnUpdateDelete)
225 EVT_UPDATE_UI(wxID_SELECTALL, wxComboBox::OnUpdateSelectAll)
b4071e91
RR
226END_EVENT_TABLE()
227
584ad2a3
MB
228bool wxComboBox::Create( wxWindow *parent, wxWindowID id,
229 const wxString& value,
230 const wxPoint& pos, const wxSize& size,
231 const wxArrayString& choices,
232 long style, const wxValidator& validator,
233 const wxString& name )
234{
235 wxCArrayString chs(choices);
236
237 return Create( parent, id, value, pos, size, chs.GetCount(),
238 chs.GetStrings(), style, validator, name );
239}
240
fd0eed64
RR
241bool wxComboBox::Create( wxWindow *parent, wxWindowID id, const wxString& value,
242 const wxPoint& pos, const wxSize& size,
243 int n, const wxString choices[],
805dd538
VZ
244 long style, const wxValidator& validator,
245 const wxString& name )
53010e52 246{
7d8268a1
WS
247 m_ignoreNextUpdate = false;
248 m_needParent = true;
249 m_acceptsFocus = true;
159b66c0 250 m_prevSelection = 0;
805dd538 251
db434467 252 if (!PreCreation( parent, pos, size ) ||
4dcaf11a
RR
253 !CreateBase( parent, id, pos, size, style, validator, name ))
254 {
223d09f6 255 wxFAIL_MSG( wxT("wxComboBox creation failed") );
7d8268a1 256 return false;
4dcaf11a 257 }
6de97a3b 258
590f50d6
RR
259#ifdef __WXGTK24__
260 if (!gtk_check_version(2,4,0))
261 {
262 m_widget = gtk_combo_box_entry_new_text();
263 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
8228b893 264
590f50d6 265 gtk_entry_set_editable( GTK_ENTRY( GTK_BIN(m_widget)->child ), TRUE );
8228b893 266
590f50d6
RR
267 for (int i = 0; i < n; i++)
268 {
269 gtk_combo_box_append_text( combobox, wxGTK_CONV( choices[i] ) );
30ed6e5c 270
590f50d6
RR
271 m_clientDataList.Append( (wxObject*)NULL );
272 m_clientObjectList.Append( (wxObject*)NULL );
273 }
274 }
275 else
276#endif
277 {
278 m_widget = gtk_combo_new();
279 GtkCombo* combo = GTK_COMBO(m_widget);
8228b893 280
590f50d6
RR
281 // Disable GTK's broken events ...
282 g_signal_handler_disconnect (combo->entry, combo->entry_change_id);
283 // ... and add surrogate handler.
284 combo->entry_change_id = g_signal_connect (combo->entry, "changed",
1fb33bdb 285 G_CALLBACK (gtkcombo_dummy_callback),
9fa72bd2 286 combo);
805dd538 287
590f50d6
RR
288 // make it more useable
289 gtk_combo_set_use_arrows_always( GTK_COMBO(m_widget), TRUE );
30ed6e5c 290
590f50d6
RR
291 // and case-sensitive
292 gtk_combo_set_case_sensitive( GTK_COMBO(m_widget), TRUE );
3ca6a5f0 293
590f50d6
RR
294 if (style & wxNO_BORDER)
295 g_object_set( GTK_ENTRY( combo->entry ), "has-frame", FALSE, NULL );
8228b893 296
590f50d6 297 GtkWidget *list = combo->list;
7d8268a1 298
590f50d6
RR
299 for (int i = 0; i < n; i++)
300 {
301 GtkWidget *list_item = gtk_list_item_new_with_label( wxGTK_CONV( choices[i] ) );
805dd538 302
590f50d6
RR
303 m_clientDataList.Append( (wxObject*)NULL );
304 m_clientObjectList.Append( (wxObject*)NULL );
805dd538 305
590f50d6 306 gtk_container_add( GTK_CONTAINER(list), list_item );
805dd538 307
590f50d6
RR
308 gtk_widget_show( list_item );
309 }
fd0eed64 310 }
805dd538 311
590f50d6 312
f03fc89f 313 m_parent->DoAddChild( this );
30ed6e5c 314
590f50d6
RR
315 GtkEntry *entry = NULL;
316#ifdef __WXGTK24__
317 if (!gtk_check_version(2,4,0))
318 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
319 else
8228b893 320#endif
590f50d6 321 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 322
590f50d6 323 m_focusWidget = GTK_WIDGET( entry );
805dd538 324
abdeb9e7 325 PostCreation(size);
53010e52 326
590f50d6
RR
327#ifdef __WXGTK24__
328 if (!gtk_check_version(2,4,0))
329 ConnectWidget( m_widget );
330 else
331#endif
332 ConnectWidget( GTK_COMBO(m_widget)->button );
805dd538 333
590f50d6
RR
334#ifdef __WXGTK24__
335 if (!gtk_check_version(2,4,0))
336 {
337 gtk_entry_set_text( entry, wxGTK_CONV(value) );
8228b893 338
590f50d6
RR
339 if (style & wxCB_READONLY)
340 gtk_entry_set_editable( entry, FALSE );
8228b893 341
590f50d6
RR
342 g_signal_connect_after (entry, "changed",
343 G_CALLBACK (gtkcombobox_text_changed_callback), this);
8228b893 344
590f50d6
RR
345 g_signal_connect_after (m_widget, "changed",
346 G_CALLBACK (gtkcombobox_changed_callback), this);
347 }
348 else
349#endif
350 {
351 GtkCombo *combo = GTK_COMBO(m_widget);
352 // MSW's combo box shows the value and the selection is -1
353 gtk_entry_set_text( entry, wxGTK_CONV(value) );
354 gtk_list_unselect_all( GTK_LIST(combo->list) );
805dd538 355
590f50d6
RR
356 if (style & wxCB_READONLY)
357 gtk_entry_set_editable( entry, FALSE );
a260fe6a 358
590f50d6
RR
359 // "show" and "hide" events are generated when user click on the combobox button which popups a list
360 // this list is the "popwin" gtk widget
361 g_signal_connect (GTK_COMBO(combo)->popwin, "hide",
1fb33bdb 362 G_CALLBACK (gtkcombo_popup_hide_callback), this);
590f50d6 363 g_signal_connect (GTK_COMBO(combo)->popwin, "show",
1fb33bdb 364 G_CALLBACK (gtkcombo_popup_show_callback), this);
590f50d6 365 g_signal_connect_after (combo->list, "select-child",
1fb33bdb 366 G_CALLBACK (gtkcombo_combo_select_child_callback),
9fa72bd2 367 this);
590f50d6
RR
368 g_signal_connect_after (entry, "changed",
369 G_CALLBACK (gtkcombo_text_changed_callback), this);
8228b893 370
590f50d6
RR
371 // This is required for tool bar support
372 // Doesn't currently work
373// wxSize setsize = GetSize();
374// gtk_widget_set_size_request( m_widget, setsize.x, setsize.y );
375 }
805dd538 376
abdeb9e7 377 SetBestSize(size); // need this too because this is a wxControlWithItems
805dd538 378
150e31d2 379
7d8268a1 380 return true;
fd0eed64
RR
381}
382
383wxComboBox::~wxComboBox()
384{
222ed1d6 385 wxList::compatibility_iterator node = m_clientObjectList.GetFirst();
fd0eed64
RR
386 while (node)
387 {
b1d4dd7a 388 wxClientData *cd = (wxClientData*)node->GetData();
fd0eed64 389 if (cd) delete cd;
b1d4dd7a 390 node = node->GetNext();
fd0eed64 391 }
7d6d2cd4
RR
392 m_clientObjectList.Clear();
393
fd0eed64 394 m_clientDataList.Clear();
6de97a3b 395}
53010e52 396
2b5f62a0
VZ
397void wxComboBox::SetFocus()
398{
399 if ( m_hasFocus )
400 {
401 // don't do anything if we already have focus
402 return;
403 }
404
405 gtk_widget_grab_focus( m_focusWidget );
406}
407
6f6f938f 408int wxComboBox::DoAppend( const wxString &item )
53010e52 409{
2a68b7a0 410 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid combobox") );
805dd538 411
590f50d6
RR
412#ifdef __WXGTK24__
413 if (!gtk_check_version(2,4,0))
414 {
415 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
416 gtk_combo_box_append_text( combobox, wxGTK_CONV( item ) );
417 }
418 else
419#endif
420 {
421 DisableEvents();
805dd538 422
590f50d6
RR
423 GtkWidget *list = GTK_COMBO(m_widget)->list;
424 GtkWidget *list_item = gtk_list_item_new_with_label( wxGTK_CONV( item ) );
805dd538 425
590f50d6 426 gtk_container_add( GTK_CONTAINER(list), list_item );
ec5d85fb 427
590f50d6
RR
428 if (GTK_WIDGET_REALIZED(m_widget))
429 {
430 gtk_widget_realize( list_item );
431 gtk_widget_realize( GTK_BIN(list_item)->child );
432 }
2b07d713 433
590f50d6
RR
434 // Apply current widget style to the new list_item
435 GtkRcStyle *style = CreateWidgetStyle();
436 if (style)
437 {
438 gtk_widget_modify_style( GTK_WIDGET( list_item ), style );
439 GtkBin *bin = GTK_BIN( list_item );
440 GtkWidget *label = GTK_WIDGET( bin->child );
441 gtk_widget_modify_style( label, style );
442 gtk_rc_style_unref( style );
443 }
805dd538 444
590f50d6 445 gtk_widget_show( list_item );
30ed6e5c 446
590f50d6
RR
447 EnableEvents();
448 }
53010e52 449
8228b893
WS
450 const size_t count = GetCount();
451
452 if ( m_clientDataList.GetCount() < count )
0a164d4c 453 m_clientDataList.Append( (wxObject*) NULL );
8228b893 454 if ( m_clientObjectList.GetCount() < count )
0a164d4c 455 m_clientObjectList.Append( (wxObject*) NULL );
805dd538 456
b0021947
VS
457 InvalidateBestSize();
458
6f6f938f 459 return count - 1;
fd0eed64
RR
460}
461
6f6f938f 462int wxComboBox::DoInsert( const wxString &item, int pos )
243dbf1a 463{
708c45a6
VZ
464 wxCHECK_MSG( !(GetWindowStyle() & wxCB_SORT), -1,
465 wxT("can't insert into sorted list"));
466
467 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid combobox") );
8228b893 468 wxCHECK_MSG( IsValidInsert(pos), -1, wxT("invalid index") );
243dbf1a 469
1dc9b42f 470 size_t count = GetCount();
6f6f938f 471
8228b893 472 if ((size_t)pos == count)
6f6f938f 473 return Append(item);
243dbf1a 474
590f50d6
RR
475#ifdef __WXGTK24__
476 if (!gtk_check_version(2,4,0))
477 {
478 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
479 gtk_combo_box_insert_text( combobox, pos, wxGTK_CONV( item ) );
480 }
481 else
482#endif
483 {
484 DisableEvents();
243dbf1a 485
590f50d6
RR
486 GtkWidget *list = GTK_COMBO(m_widget)->list;
487 GtkWidget *list_item = gtk_list_item_new_with_label( wxGTK_CONV( item ) );
243dbf1a 488
590f50d6
RR
489 GList *gitem_list = g_list_alloc ();
490 gitem_list->data = list_item;
491 gtk_list_insert_items( GTK_LIST (list), gitem_list, pos );
243dbf1a 492
590f50d6
RR
493 if (GTK_WIDGET_REALIZED(m_widget))
494 {
495 gtk_widget_realize( list_item );
496 gtk_widget_realize( GTK_BIN(list_item)->child );
243dbf1a 497
590f50d6
RR
498 ApplyWidgetStyle();
499 }
243dbf1a 500
590f50d6 501 gtk_widget_show( list_item );
243dbf1a 502
590f50d6
RR
503 EnableEvents();
504 }
8228b893 505
6f6f938f 506 count = GetCount();
243dbf1a 507
8228b893 508 if ( m_clientDataList.GetCount() < count )
0a164d4c 509 m_clientDataList.Insert( pos, (wxObject*) NULL );
8228b893 510 if ( m_clientObjectList.GetCount() < count )
0a164d4c 511 m_clientObjectList.Insert( pos, (wxObject*) NULL );
243dbf1a 512
b0021947 513 InvalidateBestSize();
243dbf1a 514
6f6f938f 515 return pos;
243dbf1a
VZ
516}
517
6f6f938f 518void wxComboBox::DoSetItemClientData( int n, void* clientData )
fd0eed64 519{
223d09f6 520 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
805dd538 521
222ed1d6 522 wxList::compatibility_iterator node = m_clientDataList.Item( n );
fd0eed64 523 if (!node) return;
805dd538 524
f5e27805 525 node->SetData( (wxObject*) clientData );
6de97a3b 526}
53010e52 527
6f6f938f 528void* wxComboBox::DoGetItemClientData( int n ) const
53010e52 529{
223d09f6 530 wxCHECK_MSG( m_widget != NULL, NULL, wxT("invalid combobox") );
805dd538 531
222ed1d6 532 wxList::compatibility_iterator node = m_clientDataList.Item( n );
805dd538 533
30ed6e5c 534 return node ? node->GetData() : NULL;
fd0eed64
RR
535}
536
6f6f938f 537void wxComboBox::DoSetItemClientObject( int n, wxClientData* clientData )
fd0eed64 538{
223d09f6 539 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
805dd538 540
222ed1d6 541 wxList::compatibility_iterator node = m_clientObjectList.Item( n );
fd0eed64 542 if (!node) return;
805dd538 543
e94e2e95 544 // wxItemContainer already deletes data for us
805dd538 545
fd0eed64 546 node->SetData( (wxObject*) clientData );
6de97a3b 547}
53010e52 548
6f6f938f 549wxClientData* wxComboBox::DoGetItemClientObject( int n ) const
53010e52 550{
223d09f6 551 wxCHECK_MSG( m_widget != NULL, (wxClientData*)NULL, wxT("invalid combobox") );
805dd538 552
222ed1d6 553 wxList::compatibility_iterator node = m_clientObjectList.Item( n );
805dd538 554
30ed6e5c 555 return node ? (wxClientData*) node->GetData() : NULL;
fd0eed64
RR
556}
557
558void wxComboBox::Clear()
559{
223d09f6 560 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
805dd538 561
461573cc 562 DisableEvents();
30ed6e5c 563
590f50d6
RR
564#ifdef __WXGTK24__
565 if (!gtk_check_version(2,4,0))
566 {
567 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
c1a3ff25
VZ
568 const size_t count = GetCount();
569 for (size_t i = 0; i < count; i++)
590f50d6
RR
570 gtk_combo_box_remove_text( combobox, 0 );
571 }
c1a3ff25
VZ
572 else // GTK+ < 2.4.0
573#endif // __WXGTK24__
590f50d6
RR
574 {
575 GtkWidget *list = GTK_COMBO(m_widget)->list;
576 gtk_list_clear_items( GTK_LIST(list), 0, GetCount() );
577 }
8228b893 578
222ed1d6 579 wxList::compatibility_iterator node = m_clientObjectList.GetFirst();
fd0eed64
RR
580 while (node)
581 {
b1d4dd7a 582 wxClientData *cd = (wxClientData*)node->GetData();
c1a3ff25 583 delete cd;
b1d4dd7a 584 node = node->GetNext();
fd0eed64 585 }
f5e27805 586 m_clientObjectList.Clear();
805dd538 587
fd0eed64 588 m_clientDataList.Clear();
30ed6e5c 589
461573cc 590 EnableEvents();
b0021947
VS
591
592 InvalidateBestSize();
6de97a3b 593}
53010e52 594
fd0eed64 595void wxComboBox::Delete( int n )
53010e52 596{
223d09f6 597 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
805dd538 598
590f50d6
RR
599#ifdef __WXGTK24__
600 if (!gtk_check_version(2,4,0))
fd0eed64 601 {
8228b893
WS
602 wxCHECK_RET( IsValid(n), wxT("invalid index") );
603
590f50d6
RR
604 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
605 gtk_combo_box_remove_text( combobox, n );
fd0eed64 606 }
590f50d6
RR
607 else
608#endif
609 {
610 GtkList *listbox = GTK_LIST( GTK_COMBO(m_widget)->list );
805dd538 611
590f50d6
RR
612 GList *child = g_list_nth( listbox->children, n );
613
614 if (!child)
615 {
616 wxFAIL_MSG(wxT("wrong index"));
617 return;
618 }
30ed6e5c 619
590f50d6 620 DisableEvents();
805dd538 621
590f50d6
RR
622 GList *list = g_list_append( (GList*) NULL, child->data );
623 gtk_list_remove_items( listbox, list );
624 g_list_free( list );
625
626 EnableEvents();
627 }
8228b893 628
222ed1d6 629 wxList::compatibility_iterator node = m_clientObjectList.Item( n );
f5e27805 630 if (node)
fd0eed64 631 {
b1d4dd7a 632 wxClientData *cd = (wxClientData*)node->GetData();
fd0eed64 633 if (cd) delete cd;
222ed1d6 634 m_clientObjectList.Erase( node );
f5e27805 635 }
805dd538 636
b1d4dd7a 637 node = m_clientDataList.Item( n );
f5e27805 638 if (node)
222ed1d6 639 m_clientDataList.Erase( node );
150e31d2 640
b0021947 641 InvalidateBestSize();
461573cc
RR
642}
643
644void wxComboBox::SetString(int n, const wxString &text)
645{
646 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
647
590f50d6
RR
648#ifdef __WXGTK24__
649 if (!gtk_check_version(2,4,0))
461573cc 650 {
590f50d6 651 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
8228b893
WS
652 wxCHECK_RET( IsValid(n), wxT("invalid index") );
653
590f50d6
RR
654 GtkTreeModel *model = gtk_combo_box_get_model( combobox );
655 GtkTreeIter iter;
656 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, n))
657 {
658 GValue value = { 0, };
659 g_value_init( &value, G_TYPE_STRING );
660 g_value_set_string( &value, wxGTK_CONV( text ) );
661 gtk_list_store_set_value( GTK_LIST_STORE(model), &iter, 0, &value );
662 g_value_unset( &value );
663 }
461573cc
RR
664 }
665 else
590f50d6 666#endif
461573cc 667 {
590f50d6 668 GtkWidget *list = GTK_COMBO(m_widget)->list;
150e31d2 669
590f50d6
RR
670 GList *child = g_list_nth( GTK_LIST(list)->children, n );
671 if (child)
672 {
673 GtkBin *bin = GTK_BIN( child->data );
674 GtkLabel *label = GTK_LABEL( bin->child );
675 gtk_label_set_text(label, wxGTK_CONV(text));
676 }
677 else
678 {
679 wxFAIL_MSG( wxT("wxComboBox: wrong index") );
680 }
681 }
8228b893 682
b0021947 683 InvalidateBestSize();
6de97a3b 684}
53010e52 685
11e62fe6 686int wxComboBox::FindString( const wxString &item, bool bCase ) const
53010e52 687{
0a164d4c 688 wxCHECK_MSG( m_widget != NULL, wxNOT_FOUND, wxT("invalid combobox") );
805dd538 689
590f50d6
RR
690#ifdef __WXGTK24__
691 if (!gtk_check_version(2,4,0))
53010e52 692 {
590f50d6
RR
693 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
694 GtkTreeModel* model = gtk_combo_box_get_model( combobox );
695 GtkTreeIter iter;
696 gtk_tree_model_get_iter_first( model, &iter );
697 if (!gtk_list_store_iter_is_valid(GTK_LIST_STORE(model), &iter ))
698 return -1;
699 int count = 0;
8228b893 700 do
590f50d6
RR
701 {
702 GValue value = { 0, };
703 gtk_tree_model_get_value( model, &iter, 0, &value );
704 wxString str = wxGTK_CONV_BACK( g_value_get_string( &value ) );
705 g_value_unset( &value );
8228b893 706
590f50d6
RR
707 if (item.IsSameAs( str, bCase ) )
708 return count;
8228b893 709
590f50d6 710 count++;
8228b893 711
590f50d6
RR
712 } while (gtk_tree_model_iter_next( model, &iter ));
713 }
714 else
715#endif
716 {
717 GtkWidget *list = GTK_COMBO(m_widget)->list;
68567a96 718
590f50d6
RR
719 GList *child = GTK_LIST(list)->children;
720 int count = 0;
721 while (child)
722 {
723 GtkBin *bin = GTK_BIN( child->data );
724 GtkLabel *label = GTK_LABEL( bin->child );
725 wxString str( wxGTK_CONV_BACK( gtk_label_get_text(label) ) );
726
727 if (item.IsSameAs( str , bCase ) )
728 return count;
30ed6e5c 729
590f50d6
RR
730 count++;
731 child = child->next;
732 }
fd0eed64 733 }
805dd538 734
7cf8cb48 735 return wxNOT_FOUND;
fd0eed64
RR
736}
737
738int wxComboBox::GetSelection() const
40eb3606 739{
590f50d6
RR
740#ifdef __WXGTK24__
741 if (!gtk_check_version(2,4,0))
742 {
743 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
744 return gtk_combo_box_get_active( combobox );
745 }
746 else
747#endif
748 // if the popup is currently opened, use the selection as it had been
749 // before it dropped down
750 return g_SelectionBeforePopup == wxID_NONE ? GetCurrentSelection()
40eb3606
VZ
751 : g_SelectionBeforePopup;
752}
753
754int wxComboBox::GetCurrentSelection() const
fd0eed64 755{
223d09f6 756 wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid combobox") );
805dd538 757
590f50d6
RR
758#ifdef __WXGTK24__
759 if (!gtk_check_version(2,4,0))
fd0eed64 760 {
590f50d6
RR
761 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
762 return gtk_combo_box_get_active( combobox );
763 }
764 else
765#endif
766 {
767 GtkWidget *list = GTK_COMBO(m_widget)->list;
768
769 GList *selection = GTK_LIST(list)->selection;
770 if (selection)
fd0eed64 771 {
590f50d6
RR
772 GList *child = GTK_LIST(list)->children;
773 int count = 0;
774 while (child)
775 {
776 if (child->data == selection->data) return count;
777 count++;
778 child = child->next;
779 }
fd0eed64 780 }
6de97a3b 781 }
805dd538 782
fd0eed64 783 return -1;
6de97a3b 784}
53010e52 785
debe6624 786wxString wxComboBox::GetString( int n ) const
53010e52 787{
0a164d4c 788 wxCHECK_MSG( m_widget != NULL, wxEmptyString, wxT("invalid combobox") );
805dd538 789
7cf8cb48 790 wxString str;
8228b893 791
590f50d6
RR
792#ifdef __WXGTK24__
793 if (!gtk_check_version(2,4,0))
fd0eed64 794 {
590f50d6
RR
795 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
796 GtkTreeModel *model = gtk_combo_box_get_model( combobox );
797 GtkTreeIter iter;
798 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, n))
799 {
800 GValue value = { 0, };
801 gtk_tree_model_get_value( model, &iter, 0, &value );
802 wxString tmp = wxGTK_CONV_BACK( g_value_get_string( &value ) );
803 g_value_unset( &value );
804 return tmp;
805 }
7cf8cb48
VZ
806 }
807 else
590f50d6 808#endif
8228b893 809 {
590f50d6
RR
810 GtkWidget *list = GTK_COMBO(m_widget)->list;
811
812 GList *child = g_list_nth( GTK_LIST(list)->children, n );
813 if (child)
814 {
815 GtkBin *bin = GTK_BIN( child->data );
816 GtkLabel *label = GTK_LABEL( bin->child );
817 str = wxGTK_CONV_BACK( gtk_label_get_text(label) );
818 }
819 else
820 {
821 wxFAIL_MSG( wxT("wxComboBox: wrong index") );
822 }
fd0eed64 823 }
805dd538 824
7cf8cb48 825 return str;
6de97a3b 826}
53010e52 827
fd0eed64 828wxString wxComboBox::GetStringSelection() const
53010e52 829{
0a164d4c 830 wxCHECK_MSG( m_widget != NULL, wxEmptyString, wxT("invalid combobox") );
805dd538 831
590f50d6
RR
832#ifdef __WXGTK24__
833 if (!gtk_check_version(2,4,0))
fd0eed64 834 {
590f50d6
RR
835 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
836 int sel = gtk_combo_box_get_active( combobox );
837 if (sel == -1)
838 return wxEmptyString;
839 return GetString( sel );
fd0eed64 840 }
590f50d6
RR
841 else
842#endif
8228b893 843 {
590f50d6
RR
844 GtkWidget *list = GTK_COMBO(m_widget)->list;
845
846 GList *selection = GTK_LIST(list)->selection;
847 if (selection)
848 {
849 GtkBin *bin = GTK_BIN( selection->data );
850 GtkLabel *label = GTK_LABEL( bin->child );
851 wxString tmp( wxGTK_CONV_BACK( gtk_label_get_text(label) ) );
852 return tmp;
853 }
805dd538 854
590f50d6
RR
855 wxFAIL_MSG( wxT("wxComboBox: no selection") );
856 }
805dd538 857
0a164d4c 858 return wxEmptyString;
6de97a3b 859}
53010e52 860
8228b893 861size_t wxComboBox::GetCount() const
53010e52 862{
223d09f6 863 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid combobox") );
805dd538 864
590f50d6
RR
865#ifdef __WXGTK24__
866 if (!gtk_check_version(2,4,0))
867 {
868 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
869 GtkTreeModel* model = gtk_combo_box_get_model( combobox );
870 GtkTreeIter iter;
871 gtk_tree_model_get_iter_first( model, &iter );
872 if (!gtk_list_store_iter_is_valid(GTK_LIST_STORE(model), &iter ))
873 return 0;
8228b893 874 size_t ret = 1;
590f50d6
RR
875 while (gtk_tree_model_iter_next( model, &iter ))
876 ret++;
877 return ret;
878 }
879 else
880#endif
8228b893 881 {
590f50d6 882 GtkWidget *list = GTK_COMBO(m_widget)->list;
805dd538 883
590f50d6 884 GList *child = GTK_LIST(list)->children;
8228b893 885 size_t count = 0;
590f50d6
RR
886 while (child) { count++; child = child->next; }
887 return count;
888 }
8228b893 889
590f50d6 890 return 0;
6de97a3b 891}
53010e52 892
debe6624 893void wxComboBox::SetSelection( int n )
53010e52 894{
223d09f6 895 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
805dd538 896
953704c1
RR
897 DisableEvents();
898
590f50d6
RR
899#ifdef __WXGTK24__
900 if (!gtk_check_version(2,4,0))
901 {
902 GtkComboBox* combobox = GTK_COMBO_BOX( m_widget );
903 gtk_combo_box_set_active( combobox, n );
904 }
905 else
906#endif
907 {
908 GtkWidget *list = GTK_COMBO(m_widget)->list;
909 gtk_list_unselect_item( GTK_LIST(list), m_prevSelection );
910 gtk_list_select_item( GTK_LIST(list), n );
911 m_prevSelection = n;
912 }
8228b893 913
953704c1 914 EnableEvents();
6de97a3b 915}
53010e52 916
fd0eed64 917wxString wxComboBox::GetValue() const
53010e52 918{
590f50d6
RR
919 GtkEntry *entry = NULL;
920#ifdef __WXGTK24__
921 if (!gtk_check_version(2,4,0))
922 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
923 else
8228b893 924#endif
590f50d6 925 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 926
2e1d7104
RR
927 wxString tmp( wxGTK_CONV_BACK( gtk_entry_get_text( entry ) ) );
928
30ed6e5c 929#if 0
2e1d7104
RR
930 for (int i = 0; i < wxStrlen(tmp.c_str()) +1; i++)
931 {
932 wxChar c = tmp[i];
933 printf( "%d ", (int) (c) );
934 }
935 printf( "\n" );
936#endif
30ed6e5c 937
fd0eed64 938 return tmp;
6de97a3b 939}
53010e52
RR
940
941void wxComboBox::SetValue( const wxString& value )
942{
223d09f6 943 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
805dd538 944
590f50d6
RR
945 GtkEntry *entry = NULL;
946#ifdef __WXGTK24__
947 if (!gtk_check_version(2,4,0))
948 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
949 else
8228b893 950#endif
590f50d6 951 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 952
0a164d4c 953 wxString tmp;
fd0eed64 954 if (!value.IsNull()) tmp = value;
590f50d6 955 gtk_entry_set_text( entry, wxGTK_CONV( tmp ) );
150e31d2 956
b0021947 957 InvalidateBestSize();
6de97a3b 958}
53010e52 959
fd0eed64 960void wxComboBox::Copy()
53010e52 961{
223d09f6 962 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
805dd538 963
590f50d6
RR
964 GtkEntry *entry = NULL;
965#ifdef __WXGTK24__
966 if (!gtk_check_version(2,4,0))
967 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
968 else
8228b893 969#endif
590f50d6 970 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 971
afa7bd1e 972 gtk_editable_copy_clipboard(GTK_EDITABLE(entry));
6de97a3b 973}
53010e52 974
fd0eed64 975void wxComboBox::Cut()
53010e52 976{
223d09f6 977 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
805dd538 978
590f50d6
RR
979 GtkEntry *entry = NULL;
980#ifdef __WXGTK24__
981 if (!gtk_check_version(2,4,0))
982 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
983 else
8228b893 984#endif
590f50d6 985 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 986
afa7bd1e 987 gtk_editable_cut_clipboard(GTK_EDITABLE(entry));
6de97a3b 988}
53010e52 989
fd0eed64 990void wxComboBox::Paste()
53010e52 991{
223d09f6 992 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
805dd538 993
590f50d6
RR
994 GtkEntry *entry = NULL;
995#ifdef __WXGTK24__
996 if (!gtk_check_version(2,4,0))
997 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
998 else
8228b893 999#endif
590f50d6 1000 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 1001
afa7bd1e 1002 gtk_editable_paste_clipboard(GTK_EDITABLE(entry));
6de97a3b 1003}
53010e52 1004
150e31d2
JS
1005void wxComboBox::Undo()
1006{
1007 // TODO
1008}
1009
1010void wxComboBox::Redo()
1011{
1012 // TODO
1013}
1014
1015void wxComboBox::SelectAll()
1016{
4e324a3f 1017 SetSelection(0, GetLastPosition());
150e31d2
JS
1018}
1019
1020bool wxComboBox::CanUndo() const
1021{
1022 // TODO
1023 return false;
1024}
1025
1026bool wxComboBox::CanRedo() const
1027{
1028 // TODO
1029 return false;
1030}
1031
1032bool wxComboBox::HasSelection() const
1033{
1034 long from, to;
1035 GetSelection(&from, &to);
1036 return from != to;
1037}
1038
1039bool wxComboBox::CanCopy() const
1040{
1041 // Can copy if there's a selection
1042 return HasSelection();
1043}
1044
1045bool wxComboBox::CanCut() const
1046{
1047 return CanCopy() && IsEditable();
1048}
1049
1050bool wxComboBox::CanPaste() const
1051{
1052 // TODO: check for text on the clipboard
1053 return IsEditable() ;
1054}
1055
1056bool wxComboBox::IsEditable() const
1057{
1058 return !HasFlag(wxCB_READONLY);
1059}
1060
1061
debe6624 1062void wxComboBox::SetInsertionPoint( long pos )
53010e52 1063{
223d09f6 1064 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
805dd538 1065
6f6f938f
VZ
1066 if ( pos == GetLastPosition() )
1067 pos = -1;
1068
590f50d6
RR
1069 GtkEntry *entry = NULL;
1070#ifdef __WXGTK24__
1071 if (!gtk_check_version(2,4,0))
1072 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
1073 else
8228b893 1074#endif
590f50d6 1075 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 1076
590f50d6 1077 gtk_entry_set_position( entry, (int)pos );
6de97a3b 1078}
53010e52 1079
fd0eed64 1080long wxComboBox::GetInsertionPoint() const
53010e52 1081{
590f50d6
RR
1082 GtkEntry *entry = NULL;
1083#ifdef __WXGTK24__
1084 if (!gtk_check_version(2,4,0))
1085 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
1086 else
8228b893 1087#endif
590f50d6 1088 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 1089
590f50d6 1090 return (long) gtk_editable_get_position(GTK_EDITABLE(entry));
6de97a3b 1091}
53010e52 1092
7d8268a1 1093wxTextPos wxComboBox::GetLastPosition() const
53010e52 1094{
590f50d6
RR
1095 GtkEntry *entry = NULL;
1096#ifdef __WXGTK24__
1097 if (!gtk_check_version(2,4,0))
1098 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
1099 else
8228b893 1100#endif
590f50d6 1101 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 1102
590f50d6 1103 int pos = entry->text_length;
fd0eed64 1104 return (long) pos-1;
6de97a3b 1105}
53010e52 1106
debe6624 1107void wxComboBox::Replace( long from, long to, const wxString& value )
53010e52 1108{
223d09f6 1109 wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
805dd538 1110
590f50d6
RR
1111 GtkEntry *entry = NULL;
1112#ifdef __WXGTK24__
1113 if (!gtk_check_version(2,4,0))
1114 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
1115 else
8228b893 1116#endif
590f50d6 1117 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 1118
fd0eed64
RR
1119 gtk_editable_delete_text( GTK_EDITABLE(entry), (gint)from, (gint)to );
1120 if (value.IsNull()) return;
1121 gint pos = (gint)to;
30ed6e5c 1122
2e1d7104
RR
1123#if wxUSE_UNICODE
1124 wxCharBuffer buffer = wxConvUTF8.cWX2MB( value );
1125 gtk_editable_insert_text( GTK_EDITABLE(entry), (const char*) buffer, strlen( (const char*) buffer ), &pos );
1126#else
8228b893 1127 gtk_editable_insert_text( GTK_EDITABLE(entry), value.c_str(), value.length(), &pos );
2e1d7104 1128#endif
6de97a3b 1129}
53010e52 1130
20d10ee1 1131void wxComboBox::SetSelection( long from, long to )
53010e52 1132{
590f50d6
RR
1133 GtkEntry *entry = NULL;
1134#ifdef __WXGTK24__
1135 if (!gtk_check_version(2,4,0))
1136 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
1137 else
8228b893 1138#endif
590f50d6 1139 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 1140
20d10ee1 1141 gtk_editable_select_region( GTK_EDITABLE(entry), (gint)from, (gint)to );
6de97a3b 1142}
53010e52 1143
150e31d2
JS
1144void wxComboBox::GetSelection( long* from, long* to ) const
1145{
590f50d6
RR
1146 GtkEntry *entry = NULL;
1147#ifdef __WXGTK24__
1148 if (!gtk_check_version(2,4,0))
1149 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
1150 else
8228b893 1151#endif
590f50d6 1152 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 1153
150e31d2
JS
1154 if (IsEditable())
1155 {
590f50d6 1156 GtkEditable *editable = GTK_EDITABLE(entry);
4e324a3f
JS
1157 gint start, end;
1158 gtk_editable_get_selection_bounds(editable, & start, & end);
1159 *from = start;
1160 *to = end;
150e31d2
JS
1161 }
1162}
1163
20d10ee1 1164void wxComboBox::SetEditable( bool editable )
53010e52 1165{
590f50d6
RR
1166 GtkEntry *entry = NULL;
1167#ifdef __WXGTK24__
1168 if (!gtk_check_version(2,4,0))
1169 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
1170 else
8228b893 1171#endif
590f50d6 1172 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 1173
20d10ee1 1174 gtk_entry_set_editable( GTK_ENTRY(entry), editable );
b4071e91
RR
1175}
1176
8a85884a
VZ
1177void wxComboBox::OnChar( wxKeyEvent &event )
1178{
12a3f227 1179 if ( event.GetKeyCode() == WXK_RETURN )
8a85884a 1180 {
461573cc 1181 // GTK automatically selects an item if its in the list
17a1ebd1
VZ
1182 wxCommandEvent eventEnter(wxEVT_COMMAND_TEXT_ENTER, GetId());
1183 eventEnter.SetString( GetValue() );
1184 eventEnter.SetInt( GetSelection() );
1185 eventEnter.SetEventObject( this );
3352cfff 1186
17a1ebd1 1187 if (!GetEventHandler()->ProcessEvent( eventEnter ))
3352cfff
RR
1188 {
1189 // This will invoke the dialog default action, such
1190 // as the clicking the default button.
1191
1192 wxWindow *top_frame = m_parent;
1193 while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
1194 top_frame = top_frame->GetParent();
1195
1196 if (top_frame && GTK_IS_WINDOW(top_frame->m_widget))
1197 {
1198 GtkWindow *window = GTK_WINDOW(top_frame->m_widget);
1199
1200 if (window->default_widget)
150e31d2 1201 gtk_widget_activate (window->default_widget);
3352cfff
RR
1202 }
1203 }
30ed6e5c 1204
461573cc
RR
1205 // Catch GTK event so that GTK doesn't open the drop
1206 // down list upon RETURN.
0878fb4c 1207 return;
8a85884a 1208 }
30ed6e5c 1209
7cf8cb48 1210 event.Skip();
8a85884a
VZ
1211}
1212
953704c1
RR
1213void wxComboBox::DisableEvents()
1214{
590f50d6
RR
1215#ifdef __WXGTK24__
1216 if (!gtk_check_version(2,4,0))
1217 {
8228b893 1218 g_signal_handlers_disconnect_by_func (GTK_BIN(m_widget)->child,
590f50d6 1219 (gpointer)gtkcombobox_text_changed_callback, this);
8228b893 1220
590f50d6
RR
1221 g_signal_handlers_disconnect_by_func (m_widget,
1222 (gpointer)gtkcombobox_changed_callback, this);
1223 }
1224 else
8228b893 1225#endif
590f50d6
RR
1226 {
1227 g_signal_handlers_disconnect_by_func (GTK_COMBO(m_widget)->list,
1228 (gpointer) gtkcombo_combo_select_child_callback, this);
8228b893 1229
590f50d6
RR
1230 g_signal_handlers_disconnect_by_func (GTK_COMBO(m_widget)->entry,
1231 (gpointer) gtkcombo_text_changed_callback, this);
1232 }
953704c1
RR
1233}
1234
1235void wxComboBox::EnableEvents()
1236{
590f50d6
RR
1237#ifdef __WXGTK24__
1238 if (!gtk_check_version(2,4,0))
1239 {
1240 g_signal_connect_after (GTK_BIN(m_widget)->child, "changed",
1241 G_CALLBACK (gtkcombobox_text_changed_callback), this);
8228b893 1242
590f50d6
RR
1243 g_signal_connect_after (m_widget, "changed",
1244 G_CALLBACK (gtkcombobox_changed_callback), this);
1245 }
1246 else
8228b893 1247#endif
590f50d6
RR
1248 {
1249 g_signal_connect_after (GTK_COMBO(m_widget)->list, "select-child",
1fb33bdb 1250 G_CALLBACK (gtkcombo_combo_select_child_callback),
9fa72bd2 1251 this);
590f50d6 1252 g_signal_connect_after (GTK_COMBO(m_widget)->entry, "changed",
1fb33bdb 1253 G_CALLBACK (gtkcombo_text_changed_callback),
9fa72bd2 1254 this );
590f50d6 1255 }
953704c1
RR
1256}
1257
b4071e91
RR
1258void wxComboBox::OnSize( wxSizeEvent &event )
1259{
590f50d6
RR
1260#ifdef __WXGTK24__
1261 if (!gtk_check_version(2,4,0))
1262 {
1263 // Do nothing
1264 }
1265 else
1266#endif
1267 {
1268 // NB: In some situations (e.g. on non-first page of a wizard, if the
1269 // size used is default size), GtkCombo widget is resized correctly,
1270 // but it's look is not updated, it's rendered as if it was much wider.
1271 // No other widgets are affected, so it looks like a bug in GTK+.
1272 // Manually requesting resize calculation (as gtk_pizza_set_size does)
1273 // fixes it.
1274 if (GTK_WIDGET_VISIBLE(m_widget))
1275 gtk_widget_queue_resize(m_widget);
1276 }
260a67b7 1277
f03fc89f 1278 event.Skip();
6de97a3b 1279}
53010e52 1280
f40fdaa3 1281void wxComboBox::DoApplyWidgetStyle(GtkRcStyle *style)
868a2826 1282{
590f50d6
RR
1283#ifdef __WXGTK24__
1284 if (!gtk_check_version(2,4,0))
1285 {
1286 // Do nothing
1287 }
1288 else
1289#endif
1290 {
f40fdaa3 1291// gtk_widget_modify_style( GTK_COMBO(m_widget)->button, syle );
ea2d542c 1292
590f50d6
RR
1293 gtk_widget_modify_style( GTK_COMBO(m_widget)->entry, style );
1294 gtk_widget_modify_style( GTK_COMBO(m_widget)->list, style );
805dd538 1295
590f50d6
RR
1296 GtkList *list = GTK_LIST( GTK_COMBO(m_widget)->list );
1297 GList *child = list->children;
1298 while (child)
1299 {
1300 gtk_widget_modify_style( GTK_WIDGET(child->data), style );
805dd538 1301
590f50d6
RR
1302 GtkBin *bin = GTK_BIN(child->data);
1303 gtk_widget_modify_style( bin->child, style );
805dd538 1304
590f50d6
RR
1305 child = child->next;
1306 }
fd0eed64 1307 }
868a2826 1308}
b4071e91 1309
fd0eed64 1310GtkWidget* wxComboBox::GetConnectWidget()
97b3455a 1311{
590f50d6
RR
1312 GtkEntry *entry = NULL;
1313#ifdef __WXGTK24__
1314 if (!gtk_check_version(2,4,0))
1315 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
1316 else
8228b893 1317#endif
590f50d6 1318 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
8228b893 1319
590f50d6 1320 return GTK_WIDGET( entry );
97b3455a
RR
1321}
1322
b4071e91
RR
1323bool wxComboBox::IsOwnGtkWindow( GdkWindow *window )
1324{
590f50d6
RR
1325 GtkEntry *entry = NULL;
1326#ifdef __WXGTK24__
1327 if (!gtk_check_version(2,4,0))
1328 {
1329 entry = GTK_ENTRY( GTK_BIN(m_widget)->child );
1330 return (window == entry->text_area);
1331 }
1332 else
8228b893 1333#endif
590f50d6
RR
1334 {
1335 entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
1336 return ( (window == entry->text_area) ||
1337 (window == GTK_COMBO(m_widget)->button->window ) );
1338 }
b4071e91 1339}
ac57418f 1340
f68586e5
VZ
1341wxSize wxComboBox::DoGetBestSize() const
1342{
db434467 1343 wxSize ret( wxControl::DoGetBestSize() );
a6fc8ae3
VZ
1344
1345 // we know better our horizontal extent: it depends on the longest string
1346 // in the combobox
a6fc8ae3
VZ
1347 if ( m_widget )
1348 {
60d85ccb
RR
1349 int width;
1350 size_t count = GetCount();
a6fc8ae3
VZ
1351 for ( size_t n = 0; n < count; n++ )
1352 {
2b1ff57f 1353 GetTextExtent( GetString(n), &width, NULL, NULL, NULL );
a6fc8ae3
VZ
1354 if ( width > ret.x )
1355 ret.x = width;
1356 }
1357 }
1358
1359 // empty combobox should have some reasonable default size too
1360 if ( ret.x < 100 )
1361 ret.x = 100;
9f884528
RD
1362
1363 CacheBestSize(ret);
db434467 1364 return ret;
f68586e5
VZ
1365}
1366
9d522606
RD
1367// static
1368wxVisualAttributes
1369wxComboBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
1370{
590f50d6
RR
1371#ifdef __WXGTK24__
1372 if (!gtk_check_version(2,4,0))
1373 return GetDefaultAttributesFromGTKWidget(gtk_combo_box_entry_new, true);
1374 else
1375#endif
1376 return GetDefaultAttributesFromGTKWidget(gtk_combo_new, true);
9d522606
RD
1377}
1378
150e31d2
JS
1379// ----------------------------------------------------------------------------
1380// standard event handling
1381// ----------------------------------------------------------------------------
1382
1383void wxComboBox::OnCut(wxCommandEvent& WXUNUSED(event))
1384{
1385 Cut();
1386}
1387
1388void wxComboBox::OnCopy(wxCommandEvent& WXUNUSED(event))
1389{
1390 Copy();
1391}
1392
1393void wxComboBox::OnPaste(wxCommandEvent& WXUNUSED(event))
1394{
1395 Paste();
1396}
1397
1398void wxComboBox::OnUndo(wxCommandEvent& WXUNUSED(event))
1399{
1400 Undo();
1401}
1402
1403void wxComboBox::OnRedo(wxCommandEvent& WXUNUSED(event))
1404{
1405 Redo();
1406}
1407
1408void wxComboBox::OnDelete(wxCommandEvent& WXUNUSED(event))
1409{
1410 long from, to;
1411 GetSelection(& from, & to);
1412 if (from != -1 && to != -1)
1413 Remove(from, to);
1414}
1415
1416void wxComboBox::OnSelectAll(wxCommandEvent& WXUNUSED(event))
1417{
1418 SetSelection(-1, -1);
1419}
1420
1421void wxComboBox::OnUpdateCut(wxUpdateUIEvent& event)
1422{
1423 event.Enable( CanCut() );
1424}
1425
1426void wxComboBox::OnUpdateCopy(wxUpdateUIEvent& event)
1427{
1428 event.Enable( CanCopy() );
1429}
1430
1431void wxComboBox::OnUpdatePaste(wxUpdateUIEvent& event)
1432{
1433 event.Enable( CanPaste() );
1434}
1435
1436void wxComboBox::OnUpdateUndo(wxUpdateUIEvent& event)
1437{
1438 event.Enable( CanUndo() );
1439}
1440
1441void wxComboBox::OnUpdateRedo(wxUpdateUIEvent& event)
1442{
1443 event.Enable( CanRedo() );
1444}
1445
1446void wxComboBox::OnUpdateDelete(wxUpdateUIEvent& event)
1447{
1448 event.Enable(HasSelection() && IsEditable()) ;
1449}
1450
1451void wxComboBox::OnUpdateSelectAll(wxUpdateUIEvent& event)
1452{
1453 event.Enable(GetLastPosition() > 0);
1454}
1455
dcf924a3 1456#endif