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