~ubuntu-dev/wxwidgets2.6/upstream-debian

« back to all changes in this revision

Viewing changes to src/gtk/combobox.cpp

  • Committer: Daniel T Chen
  • Date: 2006-06-26 10:15:11 UTC
  • Revision ID: crimsun@ubuntu.com-20060626101511-a4436cec4c6d9b35
ImportĀ DebianĀ 2.6.3.2.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        combobox.cpp
 
3
// Purpose:
 
4
// Author:      Robert Roebling
 
5
// Id:          $Id: combobox.cpp,v 1.131.2.2 2006/03/17 16:00:51 RR Exp $
 
6
// Copyright:   (c) 1998 Robert Roebling
 
7
// Licence:     wxWindows licence
 
8
/////////////////////////////////////////////////////////////////////////////
 
9
 
 
10
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
 
11
#pragma implementation "combobox.h"
 
12
#endif
 
13
 
 
14
// For compilers that support precompilation, includes "wx.h".
 
15
#include "wx/wxprec.h"
 
16
 
 
17
#include "wx/combobox.h"
 
18
 
 
19
#if wxUSE_COMBOBOX
 
20
 
 
21
#include "wx/settings.h"
 
22
#include "wx/arrstr.h"
 
23
#include "wx/intl.h"
 
24
 
 
25
#include "wx/textctrl.h"    // for wxEVT_COMMAND_TEXT_UPDATED
 
26
 
 
27
#include "wx/gtk/private.h"
 
28
 
 
29
//-----------------------------------------------------------------------------
 
30
// idle system
 
31
//-----------------------------------------------------------------------------
 
32
 
 
33
extern void wxapp_install_idle_handler();
 
34
extern bool g_isIdle;
 
35
 
 
36
//-----------------------------------------------------------------------------
 
37
// data
 
38
//-----------------------------------------------------------------------------
 
39
 
 
40
extern bool   g_blockEventsOnDrag;
 
41
static int    g_SelectionBeforePopup = wxID_NONE; // this means the popup is hidden
 
42
 
 
43
//-----------------------------------------------------------------------------
 
44
//  "changed" - typing and list item matches get changed, select-child
 
45
//              if it doesn't match an item then just get a single changed
 
46
//-----------------------------------------------------------------------------
 
47
 
 
48
extern "C" {
 
49
static void
 
50
gtk_text_changed_callback( GtkWidget *WXUNUSED(widget), wxComboBox *combo )
 
51
{
 
52
    if (g_isIdle) wxapp_install_idle_handler();
 
53
 
 
54
    if (combo->m_ignoreNextUpdate)
 
55
    {
 
56
        combo->m_ignoreNextUpdate = false;
 
57
        return;
 
58
    }
 
59
 
 
60
    if (!combo->m_hasVMT) return;
 
61
 
 
62
    wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, combo->GetId() );
 
63
    event.SetString( combo->GetValue() );
 
64
    event.SetEventObject( combo );
 
65
    combo->GetEventHandler()->ProcessEvent( event );
 
66
}
 
67
}
 
68
 
 
69
extern "C" {
 
70
static void
 
71
gtk_dummy_callback(GtkEntry *WXUNUSED(entry), GtkCombo *WXUNUSED(combo))
 
72
{
 
73
}
 
74
}
 
75
 
 
76
extern "C" {
 
77
static void
 
78
gtk_popup_hide_callback(GtkCombo *WXUNUSED(gtk_combo), wxComboBox *combo)
 
79
{
 
80
    // when the popup is hidden, throw a SELECTED event only if the combobox
 
81
    // selection changed.
 
82
    int curSelection = combo->GetCurrentSelection();
 
83
    
 
84
    // reset the selection flag to value meaning that it is hidden
 
85
    g_SelectionBeforePopup = wxID_NONE;
 
86
    
 
87
    if (g_SelectionBeforePopup != curSelection)
 
88
    {
 
89
        wxCommandEvent event( wxEVT_COMMAND_COMBOBOX_SELECTED, combo->GetId() );
 
90
        event.SetInt( curSelection );
 
91
        event.SetString( combo->GetStringSelection() );
 
92
        event.SetEventObject( combo );
 
93
        combo->GetEventHandler()->ProcessEvent( event );
 
94
 
 
95
        // for consistency with the other ports, send TEXT event
 
96
        wxCommandEvent event2( wxEVT_COMMAND_TEXT_UPDATED, combo->GetId() );
 
97
        event2.SetString( combo->GetStringSelection() );
 
98
        event2.SetEventObject( combo );
 
99
        combo->GetEventHandler()->ProcessEvent( event2 );
 
100
    }
 
101
 
 
102
}
 
103
}
 
104
 
 
105
extern "C" {
 
106
static void
 
107
gtk_popup_show_callback(GtkCombo *WXUNUSED(gtk_combo), wxComboBox *combo)
 
108
{
 
109
    // store the combobox selection value before the popup is shown
 
110
    g_SelectionBeforePopup = combo->GetCurrentSelection();
 
111
}
 
112
}
 
113
 
 
114
//-----------------------------------------------------------------------------
 
115
// "select-child" - click/cursor get select-child, changed, select-child
 
116
//-----------------------------------------------------------------------------
 
117
 
 
118
extern "C" {
 
119
static void
 
120
gtk_combo_select_child_callback( GtkList *WXUNUSED(list), GtkWidget *WXUNUSED(widget), wxComboBox *combo )
 
121
{
 
122
    if (g_isIdle) wxapp_install_idle_handler();
 
123
 
 
124
    if (!combo->m_hasVMT) return;
 
125
 
 
126
    if (g_blockEventsOnDrag) return;
 
127
 
 
128
    int curSelection = combo->GetCurrentSelection();
 
129
 
 
130
    if (combo->m_prevSelection == curSelection) return;
 
131
 
 
132
    GtkWidget *list = GTK_COMBO(combo->m_widget)->list;
 
133
    gtk_list_unselect_item( GTK_LIST(list), combo->m_prevSelection );
 
134
 
 
135
    combo->m_prevSelection = curSelection;
 
136
 
 
137
    // Quickly set the value of the combo box
 
138
    // as GTK+ does that only AFTER the event
 
139
    // is sent.
 
140
    gtk_signal_disconnect_by_func( GTK_OBJECT(GTK_COMBO(combo->GetHandle())->entry),
 
141
      GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)combo );
 
142
    combo->SetValue( combo->GetStringSelection() );
 
143
    gtk_signal_connect_after( GTK_OBJECT(GTK_COMBO(combo->GetHandle())->entry), "changed",
 
144
      GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)combo );
 
145
 
 
146
    // throw a SELECTED event only if the combobox popup is hidden (wxID_NONE)
 
147
    // because when combobox popup is shown, gtk_combo_select_child_callback is
 
148
    // called each times the mouse is over an item with a pressed button so a lot
 
149
    // of SELECTED event could be generated if the user keep the mouse button down
 
150
    // and select other items ...
 
151
    if (g_SelectionBeforePopup == wxID_NONE)
 
152
    {
 
153
        wxCommandEvent event( wxEVT_COMMAND_COMBOBOX_SELECTED, combo->GetId() );
 
154
        event.SetInt( curSelection );
 
155
        event.SetString( combo->GetStringSelection() );
 
156
        event.SetEventObject( combo );
 
157
        combo->GetEventHandler()->ProcessEvent( event );
 
158
 
 
159
        // for consistency with the other ports, don't generate text update
 
160
        // events while the user is browsing the combobox neither
 
161
        wxCommandEvent event2( wxEVT_COMMAND_TEXT_UPDATED, combo->GetId() );
 
162
        event2.SetString( combo->GetValue() );
 
163
        event2.SetEventObject( combo );
 
164
        combo->GetEventHandler()->ProcessEvent( event2 );
 
165
    }
 
166
}
 
167
}
 
168
 
 
169
//-----------------------------------------------------------------------------
 
170
// wxComboBox
 
171
//-----------------------------------------------------------------------------
 
172
 
 
173
IMPLEMENT_DYNAMIC_CLASS(wxComboBox,wxControl)
 
174
 
 
175
BEGIN_EVENT_TABLE(wxComboBox, wxControl)
 
176
    EVT_SIZE(wxComboBox::OnSize)
 
177
    EVT_CHAR(wxComboBox::OnChar)
 
178
 
 
179
    EVT_MENU(wxID_CUT, wxComboBox::OnCut)
 
180
    EVT_MENU(wxID_COPY, wxComboBox::OnCopy)
 
181
    EVT_MENU(wxID_PASTE, wxComboBox::OnPaste)
 
182
    EVT_MENU(wxID_UNDO, wxComboBox::OnUndo)
 
183
    EVT_MENU(wxID_REDO, wxComboBox::OnRedo)
 
184
    EVT_MENU(wxID_CLEAR, wxComboBox::OnDelete)
 
185
    EVT_MENU(wxID_SELECTALL, wxComboBox::OnSelectAll)
 
186
 
 
187
    EVT_UPDATE_UI(wxID_CUT, wxComboBox::OnUpdateCut)
 
188
    EVT_UPDATE_UI(wxID_COPY, wxComboBox::OnUpdateCopy)
 
189
    EVT_UPDATE_UI(wxID_PASTE, wxComboBox::OnUpdatePaste)
 
190
    EVT_UPDATE_UI(wxID_UNDO, wxComboBox::OnUpdateUndo)
 
191
    EVT_UPDATE_UI(wxID_REDO, wxComboBox::OnUpdateRedo)
 
192
    EVT_UPDATE_UI(wxID_CLEAR, wxComboBox::OnUpdateDelete)
 
193
    EVT_UPDATE_UI(wxID_SELECTALL, wxComboBox::OnUpdateSelectAll)
 
194
END_EVENT_TABLE()
 
195
 
 
196
bool wxComboBox::Create( wxWindow *parent, wxWindowID id,
 
197
                         const wxString& value,
 
198
                         const wxPoint& pos, const wxSize& size,
 
199
                         const wxArrayString& choices,
 
200
                         long style, const wxValidator& validator,
 
201
                         const wxString& name )
 
202
{
 
203
    wxCArrayString chs(choices);
 
204
 
 
205
    return Create( parent, id, value, pos, size, chs.GetCount(),
 
206
                   chs.GetStrings(), style, validator, name );
 
207
}
 
208
 
 
209
bool wxComboBox::Create( wxWindow *parent, wxWindowID id, const wxString& value,
 
210
                         const wxPoint& pos, const wxSize& size,
 
211
                         int n, const wxString choices[],
 
212
                         long style, const wxValidator& validator,
 
213
                         const wxString& name )
 
214
{
 
215
    m_ignoreNextUpdate = false;
 
216
    m_needParent = true;
 
217
    m_acceptsFocus = true;
 
218
    m_prevSelection = 0;
 
219
 
 
220
    if (!PreCreation( parent, pos, size ) ||
 
221
        !CreateBase( parent, id, pos, size, style, validator, name ))
 
222
    {
 
223
        wxFAIL_MSG( wxT("wxComboBox creation failed") );
 
224
        return false;
 
225
    }
 
226
 
 
227
    m_widget = gtk_combo_new();
 
228
    GtkCombo *combo = GTK_COMBO(m_widget);
 
229
 
 
230
    // Disable GTK's broken events ...
 
231
    gtk_signal_disconnect( GTK_OBJECT(combo->entry), combo->entry_change_id );
 
232
    // ... and add surogate handler.
 
233
    combo->entry_change_id = gtk_signal_connect (GTK_OBJECT (combo->entry), "changed",
 
234
                  (GtkSignalFunc) gtk_dummy_callback, combo);
 
235
 
 
236
    // make it more useable
 
237
    gtk_combo_set_use_arrows_always( GTK_COMBO(m_widget), TRUE );
 
238
 
 
239
    // and case-sensitive
 
240
    gtk_combo_set_case_sensitive( GTK_COMBO(m_widget), TRUE );
 
241
 
 
242
#ifdef __WXGTK20__
 
243
    if (style & wxNO_BORDER)
 
244
        g_object_set( GTK_ENTRY( combo->entry ), "has-frame", FALSE, NULL );
 
245
#endif
 
246
 
 
247
    GtkWidget *list = GTK_COMBO(m_widget)->list;
 
248
 
 
249
#ifndef __WXGTK20__
 
250
    // gtk_list_set_selection_mode( GTK_LIST(list), GTK_SELECTION_MULTIPLE );
 
251
#endif
 
252
 
 
253
    for (int i = 0; i < n; i++)
 
254
    {
 
255
        GtkWidget *list_item = gtk_list_item_new_with_label( wxGTK_CONV( choices[i] ) );
 
256
 
 
257
        m_clientDataList.Append( (wxObject*)NULL );
 
258
        m_clientObjectList.Append( (wxObject*)NULL );
 
259
 
 
260
        gtk_container_add( GTK_CONTAINER(list), list_item );
 
261
 
 
262
        gtk_widget_show( list_item );
 
263
    }
 
264
 
 
265
    m_parent->DoAddChild( this );
 
266
 
 
267
    m_focusWidget = combo->entry;
 
268
 
 
269
    PostCreation(size);
 
270
 
 
271
    ConnectWidget( combo->button );
 
272
 
 
273
    // MSW's combo box shows the value and the selection is -1
 
274
    gtk_entry_set_text( GTK_ENTRY(combo->entry), wxGTK_CONV(value) );
 
275
    gtk_list_unselect_all( GTK_LIST(combo->list) );
 
276
 
 
277
    if (style & wxCB_READONLY)
 
278
        gtk_entry_set_editable( GTK_ENTRY( combo->entry ), FALSE );
 
279
 
 
280
    // "show" and "hide" events are generated when user click on the combobox button which popups a list
 
281
    // this list is the "popwin" gtk widget
 
282
    gtk_signal_connect( GTK_OBJECT(GTK_COMBO(combo)->popwin), "hide",
 
283
                        GTK_SIGNAL_FUNC(gtk_popup_hide_callback), (gpointer)this );
 
284
    gtk_signal_connect( GTK_OBJECT(GTK_COMBO(combo)->popwin), "show",
 
285
                        GTK_SIGNAL_FUNC(gtk_popup_show_callback), (gpointer)this );
 
286
 
 
287
    gtk_signal_connect_after( GTK_OBJECT(combo->entry), "changed",
 
288
      GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this );
 
289
 
 
290
    gtk_signal_connect_after( GTK_OBJECT(combo->list), "select-child",
 
291
      GTK_SIGNAL_FUNC(gtk_combo_select_child_callback), (gpointer)this );
 
292
 
 
293
    SetBestSize(size); // need this too because this is a wxControlWithItems
 
294
 
 
295
    // This is required for tool bar support
 
296
//    wxSize setsize = GetSize();
 
297
//    gtk_widget_set_usize( m_widget, setsize.x, setsize.y );
 
298
 
 
299
    return true;
 
300
}
 
301
 
 
302
wxComboBox::~wxComboBox()
 
303
{
 
304
    wxList::compatibility_iterator node = m_clientObjectList.GetFirst();
 
305
    while (node)
 
306
    {
 
307
        wxClientData *cd = (wxClientData*)node->GetData();
 
308
        if (cd) delete cd;
 
309
        node = node->GetNext();
 
310
    }
 
311
    m_clientObjectList.Clear();
 
312
 
 
313
    m_clientDataList.Clear();
 
314
}
 
315
 
 
316
void wxComboBox::SetFocus()
 
317
{
 
318
    if ( m_hasFocus )
 
319
    {
 
320
        // don't do anything if we already have focus
 
321
        return;
 
322
    }
 
323
 
 
324
    gtk_widget_grab_focus( m_focusWidget );
 
325
}
 
326
 
 
327
int wxComboBox::DoAppend( const wxString &item )
 
328
{
 
329
    wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid combobox") );
 
330
 
 
331
    DisableEvents();
 
332
 
 
333
    GtkWidget *list = GTK_COMBO(m_widget)->list;
 
334
 
 
335
    GtkWidget *list_item = gtk_list_item_new_with_label( wxGTK_CONV( item ) );
 
336
 
 
337
    gtk_container_add( GTK_CONTAINER(list), list_item );
 
338
 
 
339
    if (GTK_WIDGET_REALIZED(m_widget))
 
340
    {
 
341
        gtk_widget_realize( list_item );
 
342
        gtk_widget_realize( GTK_BIN(list_item)->child );
 
343
    }
 
344
 
 
345
    // Apply current widget style to the new list_item
 
346
    GtkRcStyle *style = CreateWidgetStyle();
 
347
    if (style)
 
348
    {
 
349
        gtk_widget_modify_style( GTK_WIDGET( list_item ), style );
 
350
        GtkBin *bin = GTK_BIN( list_item );
 
351
        GtkWidget *label = GTK_WIDGET( bin->child );
 
352
        gtk_widget_modify_style( label, style );
 
353
        gtk_rc_style_unref( style );
 
354
    }
 
355
 
 
356
    gtk_widget_show( list_item );
 
357
 
 
358
    const int count = GetCount();
 
359
 
 
360
    if ( (int)m_clientDataList.GetCount() < count )
 
361
        m_clientDataList.Append( (wxObject*) NULL );
 
362
    if ( (int)m_clientObjectList.GetCount() < count )
 
363
        m_clientObjectList.Append( (wxObject*) NULL );
 
364
 
 
365
    EnableEvents();
 
366
 
 
367
    InvalidateBestSize();
 
368
 
 
369
    return count - 1;
 
370
}
 
371
 
 
372
int wxComboBox::DoInsert( const wxString &item, int pos )
 
373
{
 
374
    wxCHECK_MSG( !(GetWindowStyle() & wxCB_SORT), -1,
 
375
                    wxT("can't insert into sorted list"));
 
376
 
 
377
    wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid combobox") );
 
378
 
 
379
    int count = GetCount();
 
380
    wxCHECK_MSG( (pos >= 0) && (pos <= count), -1, wxT("invalid index") );
 
381
 
 
382
    if (pos == count)
 
383
        return Append(item);
 
384
 
 
385
    DisableEvents();
 
386
 
 
387
    GtkWidget *list = GTK_COMBO(m_widget)->list;
 
388
 
 
389
    GtkWidget *list_item = gtk_list_item_new_with_label( wxGTK_CONV( item ) );
 
390
 
 
391
    GList *gitem_list = g_list_alloc ();
 
392
    gitem_list->data = list_item;
 
393
    gtk_list_insert_items( GTK_LIST (list), gitem_list, pos );
 
394
 
 
395
    if (GTK_WIDGET_REALIZED(m_widget))
 
396
    {
 
397
        gtk_widget_realize( list_item );
 
398
        gtk_widget_realize( GTK_BIN(list_item)->child );
 
399
 
 
400
        ApplyWidgetStyle();
 
401
    }
 
402
 
 
403
    gtk_widget_show( list_item );
 
404
 
 
405
    count = GetCount();
 
406
 
 
407
    if ( (int)m_clientDataList.GetCount() < count )
 
408
        m_clientDataList.Insert( pos, (wxObject*) NULL );
 
409
    if ( (int)m_clientObjectList.GetCount() < count )
 
410
        m_clientObjectList.Insert( pos, (wxObject*) NULL );
 
411
 
 
412
    EnableEvents();
 
413
 
 
414
    InvalidateBestSize();
 
415
 
 
416
    return pos;
 
417
}
 
418
 
 
419
void wxComboBox::DoSetItemClientData( int n, void* clientData )
 
420
{
 
421
    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
422
 
 
423
    wxList::compatibility_iterator node = m_clientDataList.Item( n );
 
424
    if (!node) return;
 
425
 
 
426
    node->SetData( (wxObject*) clientData );
 
427
}
 
428
 
 
429
void* wxComboBox::DoGetItemClientData( int n ) const
 
430
{
 
431
    wxCHECK_MSG( m_widget != NULL, NULL, wxT("invalid combobox") );
 
432
 
 
433
    wxList::compatibility_iterator node = m_clientDataList.Item( n );
 
434
 
 
435
    return node ? node->GetData() : NULL;
 
436
}
 
437
 
 
438
void wxComboBox::DoSetItemClientObject( int n, wxClientData* clientData )
 
439
{
 
440
    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
441
 
 
442
    wxList::compatibility_iterator node = m_clientObjectList.Item( n );
 
443
    if (!node) return;
 
444
 
 
445
    // wxItemContainer already deletes data for us
 
446
 
 
447
    node->SetData( (wxObject*) clientData );
 
448
}
 
449
 
 
450
wxClientData* wxComboBox::DoGetItemClientObject( int n ) const
 
451
{
 
452
    wxCHECK_MSG( m_widget != NULL, (wxClientData*)NULL, wxT("invalid combobox") );
 
453
 
 
454
    wxList::compatibility_iterator node = m_clientObjectList.Item( n );
 
455
 
 
456
    return node ? (wxClientData*) node->GetData() : NULL;
 
457
}
 
458
 
 
459
void wxComboBox::Clear()
 
460
{
 
461
    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
462
 
 
463
    DisableEvents();
 
464
 
 
465
    GtkWidget *list = GTK_COMBO(m_widget)->list;
 
466
    gtk_list_clear_items( GTK_LIST(list), 0, GetCount() );
 
467
 
 
468
    wxList::compatibility_iterator node = m_clientObjectList.GetFirst();
 
469
    while (node)
 
470
    {
 
471
        wxClientData *cd = (wxClientData*)node->GetData();
 
472
        if (cd) delete cd;
 
473
        node = node->GetNext();
 
474
    }
 
475
    m_clientObjectList.Clear();
 
476
 
 
477
    m_clientDataList.Clear();
 
478
 
 
479
    EnableEvents();
 
480
 
 
481
    InvalidateBestSize();
 
482
}
 
483
 
 
484
void wxComboBox::Delete( int n )
 
485
{
 
486
    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
487
 
 
488
    GtkList *listbox = GTK_LIST( GTK_COMBO(m_widget)->list );
 
489
 
 
490
    GList *child = g_list_nth( listbox->children, n );
 
491
 
 
492
    if (!child)
 
493
    {
 
494
        wxFAIL_MSG(wxT("wrong index"));
 
495
        return;
 
496
    }
 
497
 
 
498
    DisableEvents();
 
499
 
 
500
    GList *list = g_list_append( (GList*) NULL, child->data );
 
501
    gtk_list_remove_items( listbox, list );
 
502
    g_list_free( list );
 
503
 
 
504
    wxList::compatibility_iterator node = m_clientObjectList.Item( n );
 
505
    if (node)
 
506
    {
 
507
        wxClientData *cd = (wxClientData*)node->GetData();
 
508
        if (cd) delete cd;
 
509
        m_clientObjectList.Erase( node );
 
510
    }
 
511
 
 
512
    node = m_clientDataList.Item( n );
 
513
    if (node)
 
514
        m_clientDataList.Erase( node );
 
515
 
 
516
    EnableEvents();
 
517
 
 
518
    InvalidateBestSize();
 
519
}
 
520
 
 
521
void wxComboBox::SetString(int n, const wxString &text)
 
522
{
 
523
    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
524
 
 
525
    GtkWidget *list = GTK_COMBO(m_widget)->list;
 
526
 
 
527
    GList *child = g_list_nth( GTK_LIST(list)->children, n );
 
528
    if (child)
 
529
    {
 
530
        GtkBin *bin = GTK_BIN( child->data );
 
531
        GtkLabel *label = GTK_LABEL( bin->child );
 
532
        gtk_label_set_text(label, wxGTK_CONV(text));
 
533
    }
 
534
    else
 
535
    {
 
536
        wxFAIL_MSG( wxT("wxComboBox: wrong index") );
 
537
    }
 
538
 
 
539
    InvalidateBestSize();
 
540
}
 
541
 
 
542
int wxComboBox::FindString( const wxString &item ) const
 
543
{
 
544
    wxCHECK_MSG( m_widget != NULL, wxNOT_FOUND, wxT("invalid combobox") );
 
545
 
 
546
    GtkWidget *list = GTK_COMBO(m_widget)->list;
 
547
 
 
548
    GList *child = GTK_LIST(list)->children;
 
549
    int count = 0;
 
550
    while (child)
 
551
    {
 
552
        GtkBin *bin = GTK_BIN( child->data );
 
553
        GtkLabel *label = GTK_LABEL( bin->child );
 
554
#ifdef __WXGTK20__
 
555
        wxString str( wxGTK_CONV_BACK( gtk_label_get_text(label) ) );
 
556
#else
 
557
        wxString str( label->label );
 
558
#endif
 
559
        if (item == str)
 
560
            return count;
 
561
 
 
562
        count++;
 
563
        child = child->next;
 
564
    }
 
565
 
 
566
    return wxNOT_FOUND;
 
567
}
 
568
 
 
569
int wxComboBox::GetSelection() const
 
570
{
 
571
    // if the popup is currently opened, use the selection as it had been
 
572
    // before it dropped down
 
573
    return g_SelectionBeforePopup == wxID_NONE ? GetCurrentSelection()
 
574
                                               : g_SelectionBeforePopup;
 
575
}
 
576
 
 
577
int wxComboBox::GetCurrentSelection() const
 
578
{
 
579
    wxCHECK_MSG( m_widget != NULL, -1, wxT("invalid combobox") );
 
580
 
 
581
    GtkWidget *list = GTK_COMBO(m_widget)->list;
 
582
 
 
583
    GList *selection = GTK_LIST(list)->selection;
 
584
    if (selection)
 
585
    {
 
586
        GList *child = GTK_LIST(list)->children;
 
587
        int count = 0;
 
588
        while (child)
 
589
        {
 
590
            if (child->data == selection->data) return count;
 
591
            count++;
 
592
            child = child->next;
 
593
        }
 
594
    }
 
595
 
 
596
    return -1;
 
597
}
 
598
 
 
599
wxString wxComboBox::GetString( int n ) const
 
600
{
 
601
    wxCHECK_MSG( m_widget != NULL, wxEmptyString, wxT("invalid combobox") );
 
602
 
 
603
    GtkWidget *list = GTK_COMBO(m_widget)->list;
 
604
 
 
605
    wxString str;
 
606
    GList *child = g_list_nth( GTK_LIST(list)->children, n );
 
607
    if (child)
 
608
    {
 
609
        GtkBin *bin = GTK_BIN( child->data );
 
610
        GtkLabel *label = GTK_LABEL( bin->child );
 
611
#ifdef __WXGTK20__
 
612
        str = wxGTK_CONV_BACK( gtk_label_get_text(label) );
 
613
#else
 
614
        str = wxString( label->label );
 
615
#endif
 
616
    }
 
617
    else
 
618
    {
 
619
        wxFAIL_MSG( wxT("wxComboBox: wrong index") );
 
620
    }
 
621
 
 
622
    return str;
 
623
}
 
624
 
 
625
wxString wxComboBox::GetStringSelection() const
 
626
{
 
627
    wxCHECK_MSG( m_widget != NULL, wxEmptyString, wxT("invalid combobox") );
 
628
 
 
629
    GtkWidget *list = GTK_COMBO(m_widget)->list;
 
630
 
 
631
    GList *selection = GTK_LIST(list)->selection;
 
632
    if (selection)
 
633
    {
 
634
        GtkBin *bin = GTK_BIN( selection->data );
 
635
        GtkLabel *label = GTK_LABEL( bin->child );
 
636
#ifdef __WXGTK20__
 
637
        wxString tmp( wxGTK_CONV_BACK( gtk_label_get_text(label) ) );
 
638
#else
 
639
        wxString tmp( label->label );
 
640
#endif
 
641
        return tmp;
 
642
    }
 
643
 
 
644
    wxFAIL_MSG( wxT("wxComboBox: no selection") );
 
645
 
 
646
    return wxEmptyString;
 
647
}
 
648
 
 
649
int wxComboBox::GetCount() const
 
650
{
 
651
    wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid combobox") );
 
652
 
 
653
    GtkWidget *list = GTK_COMBO(m_widget)->list;
 
654
 
 
655
    GList *child = GTK_LIST(list)->children;
 
656
    int count = 0;
 
657
    while (child) { count++; child = child->next; }
 
658
    return count;
 
659
}
 
660
 
 
661
void wxComboBox::SetSelection( int n )
 
662
{
 
663
    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
664
 
 
665
    DisableEvents();
 
666
 
 
667
    GtkWidget *list = GTK_COMBO(m_widget)->list;
 
668
    gtk_list_unselect_item( GTK_LIST(list), m_prevSelection );
 
669
    gtk_list_select_item( GTK_LIST(list), n );
 
670
    m_prevSelection = n;
 
671
 
 
672
    EnableEvents();
 
673
}
 
674
 
 
675
wxString wxComboBox::GetValue() const
 
676
{
 
677
    GtkEntry *entry = GTK_ENTRY( GTK_COMBO(m_widget)->entry );
 
678
    wxString tmp( wxGTK_CONV_BACK( gtk_entry_get_text( entry ) ) );
 
679
 
 
680
#if 0
 
681
    for (int i = 0; i < wxStrlen(tmp.c_str()) +1; i++)
 
682
    {
 
683
        wxChar c = tmp[i];
 
684
        printf( "%d ", (int) (c) );
 
685
    }
 
686
    printf( "\n" );
 
687
#endif
 
688
 
 
689
    return tmp;
 
690
}
 
691
 
 
692
void wxComboBox::SetValue( const wxString& value )
 
693
{
 
694
    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
695
 
 
696
    GtkWidget *entry = GTK_COMBO(m_widget)->entry;
 
697
    wxString tmp;
 
698
    if (!value.IsNull()) tmp = value;
 
699
    gtk_entry_set_text( GTK_ENTRY(entry), wxGTK_CONV( tmp ) );
 
700
 
 
701
    InvalidateBestSize();
 
702
}
 
703
 
 
704
void wxComboBox::Copy()
 
705
{
 
706
    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
707
 
 
708
    GtkWidget *entry = GTK_COMBO(m_widget)->entry;
 
709
    gtk_editable_copy_clipboard( GTK_EDITABLE(entry) DUMMY_CLIPBOARD_ARG );
 
710
}
 
711
 
 
712
void wxComboBox::Cut()
 
713
{
 
714
    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
715
 
 
716
    GtkWidget *entry = GTK_COMBO(m_widget)->entry;
 
717
    gtk_editable_cut_clipboard( GTK_EDITABLE(entry) DUMMY_CLIPBOARD_ARG );
 
718
}
 
719
 
 
720
void wxComboBox::Paste()
 
721
{
 
722
    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
723
 
 
724
    GtkWidget *entry = GTK_COMBO(m_widget)->entry;
 
725
    gtk_editable_paste_clipboard( GTK_EDITABLE(entry) DUMMY_CLIPBOARD_ARG);
 
726
}
 
727
 
 
728
void wxComboBox::Undo()
 
729
{
 
730
    // TODO
 
731
}
 
732
 
 
733
void wxComboBox::Redo()
 
734
{
 
735
    // TODO
 
736
}
 
737
 
 
738
void wxComboBox::SelectAll()
 
739
{
 
740
    SetSelection(0, GetLastPosition());
 
741
}
 
742
 
 
743
bool wxComboBox::CanUndo() const
 
744
{
 
745
    // TODO
 
746
    return false;
 
747
}
 
748
 
 
749
bool wxComboBox::CanRedo() const
 
750
{
 
751
    // TODO
 
752
    return false;
 
753
}
 
754
 
 
755
bool wxComboBox::HasSelection() const
 
756
{
 
757
    long from, to;
 
758
    GetSelection(&from, &to);
 
759
    return from != to;
 
760
}
 
761
 
 
762
bool wxComboBox::CanCopy() const
 
763
{
 
764
    // Can copy if there's a selection
 
765
    return HasSelection();
 
766
}
 
767
 
 
768
bool wxComboBox::CanCut() const
 
769
{
 
770
    return CanCopy() && IsEditable();
 
771
}
 
772
 
 
773
bool wxComboBox::CanPaste() const
 
774
{
 
775
    // TODO: check for text on the clipboard
 
776
    return IsEditable() ;
 
777
}
 
778
 
 
779
bool wxComboBox::IsEditable() const
 
780
{
 
781
    return !HasFlag(wxCB_READONLY);
 
782
}
 
783
 
 
784
 
 
785
void wxComboBox::SetInsertionPoint( long pos )
 
786
{
 
787
    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
788
 
 
789
    if ( pos == GetLastPosition() )
 
790
        pos = -1;
 
791
 
 
792
    GtkWidget *entry = GTK_COMBO(m_widget)->entry;
 
793
    gtk_entry_set_position( GTK_ENTRY(entry), (int)pos );
 
794
}
 
795
 
 
796
long wxComboBox::GetInsertionPoint() const
 
797
{
 
798
    return (long) GET_EDITABLE_POS( GTK_COMBO(m_widget)->entry );
 
799
}
 
800
 
 
801
wxTextPos wxComboBox::GetLastPosition() const
 
802
{
 
803
    GtkWidget *entry = GTK_COMBO(m_widget)->entry;
 
804
    int pos = GTK_ENTRY(entry)->text_length;
 
805
    return (long) pos-1;
 
806
}
 
807
 
 
808
void wxComboBox::Replace( long from, long to, const wxString& value )
 
809
{
 
810
    wxCHECK_RET( m_widget != NULL, wxT("invalid combobox") );
 
811
 
 
812
    GtkWidget *entry = GTK_COMBO(m_widget)->entry;
 
813
    gtk_editable_delete_text( GTK_EDITABLE(entry), (gint)from, (gint)to );
 
814
    if (value.IsNull()) return;
 
815
    gint pos = (gint)to;
 
816
 
 
817
#if wxUSE_UNICODE
 
818
    wxCharBuffer buffer = wxConvUTF8.cWX2MB( value );
 
819
    gtk_editable_insert_text( GTK_EDITABLE(entry), (const char*) buffer, strlen( (const char*) buffer ), &pos );
 
820
#else
 
821
    gtk_editable_insert_text( GTK_EDITABLE(entry), value.c_str(), value.Length(), &pos );
 
822
#endif
 
823
}
 
824
 
 
825
void wxComboBox::SetSelection( long from, long to )
 
826
{
 
827
    GtkWidget *entry = GTK_COMBO(m_widget)->entry;
 
828
    gtk_editable_select_region( GTK_EDITABLE(entry), (gint)from, (gint)to );
 
829
}
 
830
 
 
831
void wxComboBox::GetSelection( long* from, long* to ) const
 
832
{
 
833
    if (IsEditable())
 
834
    {
 
835
        GtkEditable *editable = GTK_EDITABLE(GTK_COMBO(m_widget)->entry);
 
836
#ifdef __WXGTK20__
 
837
        gint start, end;
 
838
        gtk_editable_get_selection_bounds(editable, & start, & end);
 
839
        *from = start;
 
840
        *to = end;
 
841
#else
 
842
        *from = (long) editable->selection_start_pos;
 
843
        *to = (long) editable->selection_end_pos;
 
844
#endif
 
845
    }
 
846
}
 
847
 
 
848
void wxComboBox::SetEditable( bool editable )
 
849
{
 
850
    GtkWidget *entry = GTK_COMBO(m_widget)->entry;
 
851
    gtk_entry_set_editable( GTK_ENTRY(entry), editable );
 
852
}
 
853
 
 
854
void wxComboBox::OnChar( wxKeyEvent &event )
 
855
{
 
856
    if ( event.GetKeyCode() == WXK_RETURN )
 
857
    {
 
858
        // GTK automatically selects an item if its in the list
 
859
        wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, GetId());
 
860
        event.SetString( GetValue() );
 
861
        event.SetInt( GetSelection() );
 
862
        event.SetEventObject( this );
 
863
 
 
864
        if (!GetEventHandler()->ProcessEvent( event ))
 
865
        {
 
866
            // This will invoke the dialog default action, such
 
867
            // as the clicking the default button.
 
868
 
 
869
            wxWindow *top_frame = m_parent;
 
870
            while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
 
871
                top_frame = top_frame->GetParent();
 
872
 
 
873
            if (top_frame && GTK_IS_WINDOW(top_frame->m_widget))
 
874
            {
 
875
                GtkWindow *window = GTK_WINDOW(top_frame->m_widget);
 
876
 
 
877
                if (window->default_widget)
 
878
                        gtk_widget_activate (window->default_widget);
 
879
            }
 
880
        }
 
881
 
 
882
        // Catch GTK event so that GTK doesn't open the drop
 
883
        // down list upon RETURN.
 
884
        return;
 
885
    }
 
886
 
 
887
    event.Skip();
 
888
}
 
889
 
 
890
void wxComboBox::DisableEvents()
 
891
{
 
892
    gtk_signal_disconnect_by_func( GTK_OBJECT(GTK_COMBO(m_widget)->list),
 
893
      GTK_SIGNAL_FUNC(gtk_combo_select_child_callback), (gpointer)this );
 
894
    gtk_signal_disconnect_by_func( GTK_OBJECT(GTK_COMBO(m_widget)->entry),
 
895
      GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this );
 
896
}
 
897
 
 
898
void wxComboBox::EnableEvents()
 
899
{
 
900
    gtk_signal_connect_after( GTK_OBJECT(GTK_COMBO(m_widget)->list), "select-child",
 
901
      GTK_SIGNAL_FUNC(gtk_combo_select_child_callback), (gpointer)this );
 
902
    gtk_signal_connect_after( GTK_OBJECT(GTK_COMBO(m_widget)->entry), "changed",
 
903
      GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this );
 
904
}
 
905
 
 
906
void wxComboBox::OnSize( wxSizeEvent &event )
 
907
{
 
908
    // NB: In some situations (e.g. on non-first page of a wizard, if the
 
909
    //     size used is default size), GtkCombo widget is resized correctly,
 
910
    //     but it's look is not updated, it's rendered as if it was much wider.
 
911
    //     No other widgets are affected, so it looks like a bug in GTK+.
 
912
    //     Manually requesting resize calculation (as gtk_pizza_set_size does)
 
913
    //     fixes it.
 
914
    if (GTK_WIDGET_VISIBLE(m_widget))
 
915
        gtk_widget_queue_resize(m_widget);
 
916
 
 
917
    event.Skip();
 
918
}
 
919
 
 
920
void wxComboBox::DoApplyWidgetStyle(GtkRcStyle *style)
 
921
{
 
922
//    gtk_widget_modify_style( GTK_COMBO(m_widget)->button, syle );
 
923
 
 
924
    gtk_widget_modify_style( GTK_COMBO(m_widget)->entry, style );
 
925
    gtk_widget_modify_style( GTK_COMBO(m_widget)->list, style );
 
926
 
 
927
    GtkList *list = GTK_LIST( GTK_COMBO(m_widget)->list );
 
928
    GList *child = list->children;
 
929
    while (child)
 
930
    {
 
931
        gtk_widget_modify_style( GTK_WIDGET(child->data), style );
 
932
 
 
933
        GtkBin *bin = GTK_BIN(child->data);
 
934
        gtk_widget_modify_style( bin->child, style );
 
935
 
 
936
        child = child->next;
 
937
    }
 
938
}
 
939
 
 
940
GtkWidget* wxComboBox::GetConnectWidget()
 
941
{
 
942
    return GTK_COMBO(m_widget)->entry;
 
943
}
 
944
 
 
945
bool wxComboBox::IsOwnGtkWindow( GdkWindow *window )
 
946
{
 
947
    return ( (window == GTK_ENTRY( GTK_COMBO(m_widget)->entry )->text_area) ||
 
948
             (window == GTK_COMBO(m_widget)->button->window ) );
 
949
}
 
950
 
 
951
wxSize wxComboBox::DoGetBestSize() const
 
952
{
 
953
    wxSize ret( wxControl::DoGetBestSize() );
 
954
 
 
955
    // we know better our horizontal extent: it depends on the longest string
 
956
    // in the combobox
 
957
    if ( m_widget )
 
958
    {
 
959
        int width;
 
960
        size_t count = GetCount();
 
961
        for ( size_t n = 0; n < count; n++ )
 
962
        {
 
963
            GetTextExtent( GetString(n), &width, NULL, NULL, NULL );
 
964
            if ( width > ret.x )
 
965
                ret.x = width;
 
966
        }
 
967
    }
 
968
 
 
969
    // empty combobox should have some reasonable default size too
 
970
    if ( ret.x < 100 )
 
971
        ret.x = 100;
 
972
 
 
973
    CacheBestSize(ret);
 
974
    return ret;
 
975
}
 
976
 
 
977
// static
 
978
wxVisualAttributes
 
979
wxComboBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
 
980
{
 
981
    return GetDefaultAttributesFromGTKWidget(gtk_combo_new, true);
 
982
}
 
983
 
 
984
// ----------------------------------------------------------------------------
 
985
// standard event handling
 
986
// ----------------------------------------------------------------------------
 
987
 
 
988
void wxComboBox::OnCut(wxCommandEvent& WXUNUSED(event))
 
989
{
 
990
    Cut();
 
991
}
 
992
 
 
993
void wxComboBox::OnCopy(wxCommandEvent& WXUNUSED(event))
 
994
{
 
995
    Copy();
 
996
}
 
997
 
 
998
void wxComboBox::OnPaste(wxCommandEvent& WXUNUSED(event))
 
999
{
 
1000
    Paste();
 
1001
}
 
1002
 
 
1003
void wxComboBox::OnUndo(wxCommandEvent& WXUNUSED(event))
 
1004
{
 
1005
    Undo();
 
1006
}
 
1007
 
 
1008
void wxComboBox::OnRedo(wxCommandEvent& WXUNUSED(event))
 
1009
{
 
1010
    Redo();
 
1011
}
 
1012
 
 
1013
void wxComboBox::OnDelete(wxCommandEvent& WXUNUSED(event))
 
1014
{
 
1015
    long from, to;
 
1016
    GetSelection(& from, & to);
 
1017
    if (from != -1 && to != -1)
 
1018
        Remove(from, to);
 
1019
}
 
1020
 
 
1021
void wxComboBox::OnSelectAll(wxCommandEvent& WXUNUSED(event))
 
1022
{
 
1023
    SetSelection(-1, -1);
 
1024
}
 
1025
 
 
1026
void wxComboBox::OnUpdateCut(wxUpdateUIEvent& event)
 
1027
{
 
1028
    event.Enable( CanCut() );
 
1029
}
 
1030
 
 
1031
void wxComboBox::OnUpdateCopy(wxUpdateUIEvent& event)
 
1032
{
 
1033
    event.Enable( CanCopy() );
 
1034
}
 
1035
 
 
1036
void wxComboBox::OnUpdatePaste(wxUpdateUIEvent& event)
 
1037
{
 
1038
    event.Enable( CanPaste() );
 
1039
}
 
1040
 
 
1041
void wxComboBox::OnUpdateUndo(wxUpdateUIEvent& event)
 
1042
{
 
1043
    event.Enable( CanUndo() );
 
1044
}
 
1045
 
 
1046
void wxComboBox::OnUpdateRedo(wxUpdateUIEvent& event)
 
1047
{
 
1048
    event.Enable( CanRedo() );
 
1049
}
 
1050
 
 
1051
void wxComboBox::OnUpdateDelete(wxUpdateUIEvent& event)
 
1052
{
 
1053
    event.Enable(HasSelection() && IsEditable()) ;
 
1054
}
 
1055
 
 
1056
void wxComboBox::OnUpdateSelectAll(wxUpdateUIEvent& event)
 
1057
{
 
1058
    event.Enable(GetLastPosition() > 0);
 
1059
}
 
1060
 
 
1061
#endif