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