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