Some work on tabbing and menu accels,
[wxWidgets.git] / src / gtk1 / listbox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: listbox.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11 #ifdef __GNUG__
12 #pragma implementation "listbox.h"
13 #endif
14
15 #include "wx/listbox.h"
16
17 #if wxUSE_LISTBOX
18
19 #include "wx/dynarray.h"
20 #include "wx/utils.h"
21 #include "wx/intl.h"
22 #include "wx/checklst.h"
23 #include "wx/settings.h"
24
25 #if wxUSE_TOOLTIPS
26 #include "wx/tooltip.h"
27 #endif
28
29 #include "gdk/gdk.h"
30 #include "gtk/gtk.h"
31 #include "gdk/gdkkeysyms.h"
32
33 //-----------------------------------------------------------------------------
34 // idle system
35 //-----------------------------------------------------------------------------
36
37 extern void wxapp_install_idle_handler();
38 extern bool g_isIdle;
39
40 //-------------------------------------------------------------------------
41 // conditional compilation
42 //-------------------------------------------------------------------------
43
44 #if (GTK_MINOR_VERSION > 0)
45 #define NEW_GTK_SCROLL_CODE
46 #endif
47
48 //-----------------------------------------------------------------------------
49 // private functions
50 //-----------------------------------------------------------------------------
51
52 #if wxUSE_CHECKLISTBOX
53
54 #define CHECKBOX_STRING "[-] "
55
56 // checklistboxes have "[±] " prepended to their lables, this macro removes it
57 // (NB: 4 below is the length of CHECKBOX_STRING above)
58 //
59 // the argument to it is a "const char *" pointer
60 #define GET_REAL_LABEL(label) ((m_hasCheckBoxes)?(label)+4 : (label))
61
62 #else // !wxUSE_CHECKLISTBOX
63
64 #define GET_REAL_LABEL(label) (label)
65
66 #endif // wxUSE_CHECKLISTBOX
67
68 //-----------------------------------------------------------------------------
69 // data
70 //-----------------------------------------------------------------------------
71
72 extern bool g_blockEventsOnDrag;
73 extern bool g_blockEventsOnScroll;
74 extern wxCursor g_globalCursor;
75
76 static bool g_hasDoubleClicked = FALSE;
77
78 //-----------------------------------------------------------------------------
79 // "button_release_event"
80 //-----------------------------------------------------------------------------
81
82 /* we would normally emit a wxEVT_COMMAND_LISTBOX_DOUBLECLICKED event once
83 a GDK_2BUTTON_PRESS occurs, but this has the particular problem of the
84 listbox keeping the focus until it receives a GDK_BUTTON_RELEASE event.
85 this can lead to race conditions so that we emit the dclick event
86 after the GDK_BUTTON_RELEASE event after the GDK_2BUTTON_PRESS event */
87
88 static gint
89 gtk_listbox_button_release_callback( GtkWidget * WXUNUSED(widget),
90 GdkEventButton * WXUNUSED(gdk_event),
91 wxListBox *listbox )
92 {
93 if (g_isIdle) wxapp_install_idle_handler();
94
95 if (g_blockEventsOnDrag) return FALSE;
96 if (g_blockEventsOnScroll) return FALSE;
97
98 if (!listbox->m_hasVMT) return FALSE;
99
100 if (!g_hasDoubleClicked) return FALSE;
101
102 wxCommandEvent event( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, listbox->GetId() );
103 event.SetEventObject( listbox );
104
105 wxArrayInt aSelections;
106 int n, count = listbox->GetSelections(aSelections);
107 if ( count > 0 )
108 {
109 n = aSelections[0];
110 if ( listbox->HasClientObjectData() )
111 event.SetClientObject( listbox->GetClientObject(n) );
112 else if ( listbox->HasClientUntypedData() )
113 event.SetClientData( listbox->GetClientData(n) );
114 event.SetString( listbox->GetString(n) );
115 }
116 else
117 {
118 n = -1;
119 }
120
121 event.m_commandInt = n;
122
123 listbox->GetEventHandler()->ProcessEvent( event );
124
125 return FALSE;
126 }
127
128 //-----------------------------------------------------------------------------
129 // "button_press_event"
130 //-----------------------------------------------------------------------------
131
132 static gint
133 gtk_listbox_button_press_callback( GtkWidget *widget,
134 GdkEventButton *gdk_event,
135 wxListBox *listbox )
136 {
137 if (g_isIdle) wxapp_install_idle_handler();
138
139 if (g_blockEventsOnDrag) return FALSE;
140 if (g_blockEventsOnScroll) return FALSE;
141
142 if (!listbox->m_hasVMT) return FALSE;
143
144 int sel = listbox->GtkGetIndex( widget );
145
146 #if wxUSE_CHECKLISTBOX
147 if ((listbox->m_hasCheckBoxes) && (gdk_event->x < 15) && (gdk_event->type != GDK_2BUTTON_PRESS))
148 {
149 wxCheckListBox *clb = (wxCheckListBox *)listbox;
150
151 clb->Check( sel, !clb->IsChecked(sel) );
152
153 wxCommandEvent event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, listbox->GetId() );
154 event.SetEventObject( listbox );
155 event.SetInt( sel );
156 listbox->GetEventHandler()->ProcessEvent( event );
157 }
158 #endif // wxUSE_CHECKLISTBOX
159
160 /* emit wxEVT_COMMAND_LISTBOX_DOUBLECLICKED later */
161 g_hasDoubleClicked = (gdk_event->type == GDK_2BUTTON_PRESS);
162
163 return FALSE;
164 }
165
166 //-----------------------------------------------------------------------------
167 // "key_press_event"
168 //-----------------------------------------------------------------------------
169
170 static gint
171 gtk_listbox_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxListBox *listbox )
172 {
173 if (g_isIdle)
174 wxapp_install_idle_handler();
175
176 if (g_blockEventsOnDrag)
177 return FALSE;
178
179 bool ret = FALSE;
180
181 if ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab))
182 {
183 wxNavigationKeyEvent new_event;
184 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
185 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
186 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
187 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
188 new_event.SetCurrentFocus( listbox );
189 ret = listbox->GetEventHandler()->ProcessEvent( new_event );
190 }
191
192 #if wxUSE_CHECKLISTBOX
193 if ((gdk_event->keyval != ' ') && (listbox->m_hasCheckBoxes) && (!ret))
194 {
195 int sel = listbox->GtkGetIndex( widget );
196
197 wxCheckListBox *clb = (wxCheckListBox *)listbox;
198
199 clb->Check( sel, !clb->IsChecked(sel) );
200
201 wxCommandEvent new_event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, listbox->GetId() );
202 new_event.SetEventObject( listbox );
203 new_event.SetInt( sel );
204 ret = listbox->GetEventHandler()->ProcessEvent( new_event );
205 }
206 #endif // wxUSE_CHECKLISTBOX
207
208 if (ret)
209 {
210 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
211 return TRUE;
212 }
213
214 return FALSE;
215 }
216
217 //-----------------------------------------------------------------------------
218 // "select" and "deselect"
219 //-----------------------------------------------------------------------------
220
221 static void gtk_listitem_select_callback( GtkWidget *WXUNUSED(widget), wxListBox *listbox );
222
223 static void gtk_listitem_deselect_callback( GtkWidget *widget, wxListBox *listbox )
224 {
225 gtk_listitem_select_callback( widget, listbox );
226 }
227
228 static void gtk_listitem_select_callback( GtkWidget *WXUNUSED(widget), wxListBox *listbox )
229 {
230 if (g_isIdle) wxapp_install_idle_handler();
231
232 if (!listbox->m_hasVMT) return;
233 if (g_blockEventsOnDrag) return;
234
235 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, listbox->GetId() );
236 event.SetEventObject( listbox );
237
238 wxArrayInt aSelections;
239 int n, count = listbox->GetSelections(aSelections);
240 if ( count > 0 )
241 {
242 n = aSelections[0];
243 if ( listbox->HasClientObjectData() )
244 event.SetClientObject( listbox->GetClientObject(n) );
245 else if ( listbox->HasClientUntypedData() )
246 event.SetClientData( listbox->GetClientData(n) );
247 event.SetString( listbox->GetString(n) );
248 }
249 else
250 {
251 n = -1;
252 }
253
254 event.m_commandInt = n;
255
256 listbox->GetEventHandler()->ProcessEvent( event );
257 }
258
259 //-----------------------------------------------------------------------------
260 // wxListBox
261 //-----------------------------------------------------------------------------
262
263 IMPLEMENT_DYNAMIC_CLASS(wxListBox,wxControl)
264
265 // ----------------------------------------------------------------------------
266 // construction
267 // ----------------------------------------------------------------------------
268
269 wxListBox::wxListBox()
270 {
271 m_list = (GtkList *) NULL;
272 #if wxUSE_CHECKLISTBOX
273 m_hasCheckBoxes = FALSE;
274 #endif // wxUSE_CHECKLISTBOX
275 }
276
277 bool wxListBox::Create( wxWindow *parent, wxWindowID id,
278 const wxPoint &pos, const wxSize &size,
279 int n, const wxString choices[],
280 long style, const wxValidator& validator,
281 const wxString &name )
282 {
283 m_needParent = TRUE;
284 m_acceptsFocus = TRUE;
285
286 if (!PreCreation( parent, pos, size ) ||
287 !CreateBase( parent, id, pos, size, style, validator, name ))
288 {
289 wxFAIL_MSG( wxT("wxListBox creation failed") );
290 return FALSE;
291 }
292
293 m_widget = gtk_scrolled_window_new( (GtkAdjustment*) NULL, (GtkAdjustment*) NULL );
294 if (style & wxLB_ALWAYS_SB)
295 {
296 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
297 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS );
298 }
299 else
300 {
301 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
302 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
303 }
304
305 m_list = GTK_LIST( gtk_list_new() );
306
307 GtkSelectionMode mode = GTK_SELECTION_BROWSE;
308 if (style & wxLB_MULTIPLE)
309 mode = GTK_SELECTION_MULTIPLE;
310 else if (style & wxLB_EXTENDED)
311 mode = GTK_SELECTION_EXTENDED;
312
313 gtk_list_set_selection_mode( GTK_LIST(m_list), mode );
314
315 #ifdef NEW_GTK_SCROLL_CODE
316 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(m_widget), GTK_WIDGET(m_list) );
317 #else
318 gtk_container_add( GTK_CONTAINER(m_widget), GTK_WIDGET(m_list) );
319 #endif
320
321 /* make list scroll when moving the focus down using cursor keys */
322 gtk_container_set_focus_vadjustment(
323 GTK_CONTAINER(m_list),
324 gtk_scrolled_window_get_vadjustment(
325 GTK_SCROLLED_WINDOW(m_widget)));
326
327 gtk_widget_show( GTK_WIDGET(m_list) );
328
329 wxSize newSize = size;
330 if (newSize.x == -1)
331 newSize.x = 100;
332 if (newSize.y == -1)
333 newSize.y = 110;
334 SetSize( newSize.x, newSize.y );
335
336 if ( style & wxLB_SORT )
337 {
338 // this will change DoAppend() behaviour
339 m_strings = new wxSortedArrayString;
340 }
341 else
342 {
343 m_strings = (wxSortedArrayString *)NULL;
344 }
345
346 for (int i = 0; i < n; i++)
347 {
348 // add one by one
349 DoAppend(choices[i]);
350 }
351
352 m_parent->DoAddChild( this );
353
354 PostCreation();
355
356 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOW ) );
357 SetForegroundColour( parent->GetForegroundColour() );
358 SetFont( parent->GetFont() );
359
360 Show( TRUE );
361
362 return TRUE;
363 }
364
365 wxListBox::~wxListBox()
366 {
367 Clear();
368 }
369
370 void wxListBox::DoInsertItems(const wxArrayString& items, int pos)
371 {
372 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
373
374 // VZ: notice that InsertItems knows nothing about sorting, so calling it
375 // from outside (and not from our own Append) is likely to break
376 // everything
377
378 // code elsewhere supposes we have as many items in m_clientList as items
379 // in the listbox
380 wxASSERT_MSG( m_clientList.GetCount() == (size_t)GetCount(),
381 wxT("bug in client data management") );
382
383 GList *children = m_list->children;
384 int length = g_list_length(children);
385
386 wxCHECK_RET( pos <= length, wxT("invalid index in wxListBox::InsertItems") );
387
388 size_t nItems = items.GetCount();
389
390 if (pos == length)
391 {
392 for ( size_t n = 0; n < nItems; n++ )
393 {
394 GtkAddItem( items[n] );
395
396 m_clientList.Append((wxObject *)NULL);
397 }
398 }
399 else
400 {
401 wxNode *node = m_clientList.Nth( pos );
402 for ( size_t n = 0; n < nItems; n++ )
403 {
404 GtkAddItem( items[n], pos+n );
405
406 m_clientList.Insert( node, (wxObject *)NULL );
407 }
408 }
409
410 wxASSERT_MSG( m_clientList.GetCount() == (size_t)GetCount(),
411 wxT("bug in client data management") );
412 }
413
414 int wxListBox::DoAppend( const wxString& item )
415 {
416 if (m_strings)
417 {
418 // need to determine the index
419 int index = m_strings->Add( item );
420
421 // only if not at the end anyway
422 if (index != GetCount())
423 {
424 GtkAddItem( item, index );
425
426 wxNode *node = m_clientList.Nth( index );
427 m_clientList.Insert( node, (wxObject *)NULL );
428
429 return index;
430 }
431 }
432
433 GtkAddItem(item);
434
435 m_clientList.Append((wxObject *)NULL);
436
437 return GetCount() - 1;
438 }
439
440 void wxListBox::GtkAddItem( const wxString &item, int pos )
441 {
442 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
443
444 GtkWidget *list_item;
445
446 wxString label(item);
447 #if wxUSE_CHECKLISTBOX
448 if (m_hasCheckBoxes)
449 {
450 label.Prepend(CHECKBOX_STRING);
451 }
452 #endif // wxUSE_CHECKLISTBOX
453
454 list_item = gtk_list_item_new_with_label( label.mbc_str() );
455
456 GList *gitem_list = g_list_alloc ();
457 gitem_list->data = list_item;
458
459 if (pos == -1)
460 gtk_list_append_items( GTK_LIST (m_list), gitem_list );
461 else
462 gtk_list_insert_items( GTK_LIST (m_list), gitem_list, pos );
463
464 gtk_signal_connect( GTK_OBJECT(list_item), "select",
465 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
466
467 if (HasFlag(wxLB_MULTIPLE))
468 gtk_signal_connect( GTK_OBJECT(list_item), "deselect",
469 GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback), (gpointer)this );
470
471 gtk_signal_connect( GTK_OBJECT(list_item),
472 "button_press_event",
473 (GtkSignalFunc)gtk_listbox_button_press_callback,
474 (gpointer) this );
475
476 gtk_signal_connect_after( GTK_OBJECT(list_item),
477 "button_release_event",
478 (GtkSignalFunc)gtk_listbox_button_release_callback,
479 (gpointer) this );
480
481 gtk_signal_connect( GTK_OBJECT(list_item),
482 "key_press_event",
483 (GtkSignalFunc)gtk_listbox_key_press_callback,
484 (gpointer)this );
485
486 gtk_widget_show( list_item );
487
488 ConnectWidget( list_item );
489
490 if (GTK_WIDGET_REALIZED(m_widget))
491 {
492 gtk_widget_realize( list_item );
493 gtk_widget_realize( GTK_BIN(list_item)->child );
494
495 // Apply current widget style to the new list_item
496 if (m_widgetStyle)
497 {
498 gtk_widget_set_style( GTK_WIDGET( list_item ), m_widgetStyle );
499 GtkBin *bin = GTK_BIN( list_item );
500 GtkWidget *label = GTK_WIDGET( bin->child );
501 gtk_widget_set_style( label, m_widgetStyle );
502 }
503
504 #if wxUSE_TOOLTIPS
505 if (m_tooltip) m_tooltip->Apply( this );
506 #endif
507 }
508 }
509
510 void wxListBox::DoSetItems( const wxArrayString& items,
511 void **clientData)
512 {
513 Clear();
514
515 DoInsertItems(items, 0);
516
517 if ( clientData )
518 {
519 size_t count = items.GetCount();
520 for ( size_t n = 0; n < count; n++ )
521 {
522 SetClientData(n, clientData[n]);
523 }
524 }
525 }
526
527 // ----------------------------------------------------------------------------
528 // client data
529 // ----------------------------------------------------------------------------
530
531 void wxListBox::DoSetItemClientData( int n, void* clientData )
532 {
533 wxCHECK_RET( m_widget != NULL, wxT("invalid listbox control") );
534
535 wxNode *node = m_clientList.Nth( n );
536 wxCHECK_RET( node, wxT("invalid index in wxListBox::DoSetItemClientData") );
537
538 node->SetData( (wxObject*) clientData );
539 }
540
541 void* wxListBox::DoGetItemClientData( int n ) const
542 {
543 wxCHECK_MSG( m_widget != NULL, NULL, wxT("invalid listbox control") );
544
545 wxNode *node = m_clientList.Nth( n );
546 wxCHECK_MSG( node, NULL, wxT("invalid index in wxListBox::DoGetItemClientData") );
547
548 return node->Data();
549 }
550
551 void wxListBox::DoSetItemClientObject( int n, wxClientData* clientData )
552 {
553 wxCHECK_RET( m_widget != NULL, wxT("invalid listbox control") );
554
555 wxNode *node = m_clientList.Nth( n );
556 wxCHECK_RET( node, wxT("invalid index in wxListBox::DoSetItemClientObject") );
557
558 wxClientData *cd = (wxClientData*) node->Data();
559 delete cd;
560
561 node->SetData( (wxObject*) clientData );
562 }
563
564 wxClientData* wxListBox::DoGetItemClientObject( int n ) const
565 {
566 wxCHECK_MSG( m_widget != NULL, (wxClientData*) NULL, wxT("invalid listbox control") );
567
568 wxNode *node = m_clientList.Nth( n );
569 wxCHECK_MSG( node, (wxClientData *)NULL,
570 wxT("invalid index in wxListBox::DoGetItemClientObject") );
571
572 return (wxClientData*) node->Data();
573 }
574
575 void wxListBox::Clear()
576 {
577 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
578
579 gtk_list_clear_items( m_list, 0, Number() );
580
581 if ( HasClientObjectData() )
582 {
583 // destroy the data (due to Robert's idea of using wxList<wxObject>
584 // and not wxList<wxClientData> we can't just say
585 // m_clientList.DeleteContents(TRUE) - this would crash!
586 wxNode *node = m_clientList.First();
587 while ( node )
588 {
589 delete (wxClientData *)node->Data();
590 node = node->Next();
591 }
592 }
593 m_clientList.Clear();
594
595 if ( m_strings )
596 m_strings->Clear();
597 }
598
599 void wxListBox::Delete( int n )
600 {
601 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
602
603 GList *child = g_list_nth( m_list->children, n );
604
605 wxCHECK_RET( child, wxT("wrong listbox index") );
606
607 GList *list = g_list_append( (GList*) NULL, child->data );
608 gtk_list_remove_items( m_list, list );
609 g_list_free( list );
610
611 wxNode *node = m_clientList.Nth( n );
612 if ( node )
613 {
614 if ( m_clientDataItemsType == ClientData_Object )
615 {
616 wxClientData *cd = (wxClientData*)node->Data();
617 delete cd;
618 }
619
620 m_clientList.DeleteNode( node );
621 }
622
623 if ( m_strings )
624 m_strings->Remove(n);
625 }
626
627 // ----------------------------------------------------------------------------
628 // string list access
629 // ----------------------------------------------------------------------------
630
631 void wxListBox::SetString( int n, const wxString &string )
632 {
633 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
634
635 GList *child = g_list_nth( m_list->children, n );
636 if (child)
637 {
638 GtkBin *bin = GTK_BIN( child->data );
639 GtkLabel *label = GTK_LABEL( bin->child );
640
641 wxString str;
642 #if wxUSE_CHECKLISTBOX
643 if (m_hasCheckBoxes)
644 str += CHECKBOX_STRING;
645 #endif // wxUSE_CHECKLISTBOX
646 str += string;
647
648 gtk_label_set( label, str.mbc_str() );
649 }
650 else
651 {
652 wxFAIL_MSG(wxT("wrong listbox index"));
653 }
654 }
655
656 wxString wxListBox::GetString( int n ) const
657 {
658 wxCHECK_MSG( m_list != NULL, wxT(""), wxT("invalid listbox") );
659
660 GList *child = g_list_nth( m_list->children, n );
661 if (child)
662 {
663 GtkBin *bin = GTK_BIN( child->data );
664 GtkLabel *label = GTK_LABEL( bin->child );
665
666 wxString str = wxString(GET_REAL_LABEL(label->label),*wxConvCurrent);
667
668 return str;
669 }
670
671 wxFAIL_MSG(wxT("wrong listbox index"));
672
673 return wxT("");
674 }
675
676 int wxListBox::GetCount() const
677 {
678 wxCHECK_MSG( m_list != NULL, -1, wxT("invalid listbox") );
679
680 GList *children = m_list->children;
681 return g_list_length(children);
682 }
683
684 int wxListBox::FindString( const wxString &item ) const
685 {
686 wxCHECK_MSG( m_list != NULL, -1, wxT("invalid listbox") );
687
688 GList *child = m_list->children;
689 int count = 0;
690 while (child)
691 {
692 GtkBin *bin = GTK_BIN( child->data );
693 GtkLabel *label = GTK_LABEL( bin->child );
694
695 wxString str = wxString(GET_REAL_LABEL(label->label),*wxConvCurrent);
696
697 if (str == item)
698 return count;
699
700 count++;
701 child = child->next;
702 }
703
704 // it's not an error if the string is not found -> no wxCHECK
705
706 return wxNOT_FOUND;
707 }
708
709 // ----------------------------------------------------------------------------
710 // selection
711 // ----------------------------------------------------------------------------
712
713 int wxListBox::GetSelection() const
714 {
715 wxCHECK_MSG( m_list != NULL, -1, wxT("invalid listbox") );
716
717 GList *child = m_list->children;
718 int count = 0;
719 while (child)
720 {
721 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED) return count;
722 count++;
723 child = child->next;
724 }
725 return -1;
726 }
727
728 int wxListBox::GetSelections( wxArrayInt& aSelections ) const
729 {
730 wxCHECK_MSG( m_list != NULL, -1, wxT("invalid listbox") );
731
732 // get the number of selected items first
733 GList *child = m_list->children;
734 int count = 0;
735 for (child = m_list->children; child != NULL; child = child->next)
736 {
737 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED)
738 count++;
739 }
740
741 aSelections.Empty();
742
743 if (count > 0)
744 {
745 // now fill the list
746 aSelections.Alloc(count); // optimization attempt
747 int i = 0;
748 for (child = m_list->children; child != NULL; child = child->next, i++)
749 {
750 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED)
751 aSelections.Add(i);
752 }
753 }
754
755 return count;
756 }
757
758 bool wxListBox::IsSelected( int n ) const
759 {
760 wxCHECK_MSG( m_list != NULL, FALSE, wxT("invalid listbox") );
761
762 GList *target = g_list_nth( m_list->children, n );
763 if (target)
764 {
765 GList *child = m_list->selection;
766 while (child)
767 {
768 if (child->data == target->data) return TRUE;
769 child = child->next;
770 }
771 }
772
773 wxFAIL_MSG(wxT("wrong listbox index"));
774
775 return FALSE;
776 }
777
778 void wxListBox::SetSelection( int n, bool select )
779 {
780 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
781
782 GtkDisableEvents();
783
784 if (select)
785 gtk_list_select_item( m_list, n );
786 else
787 gtk_list_unselect_item( m_list, n );
788
789 GtkEnableEvents();
790 }
791
792 void wxListBox::DoSetFirstItem( int WXUNUSED(n) )
793 {
794 wxFAIL_MSG(wxT("wxListBox::SetFirstItem not implemented"));
795 }
796
797 // ----------------------------------------------------------------------------
798 // helpers
799 // ----------------------------------------------------------------------------
800
801 int wxListBox::GtkGetIndex( GtkWidget *item ) const
802 {
803 if (item)
804 {
805 GList *child = m_list->children;
806 int count = 0;
807 while (child)
808 {
809 if (GTK_WIDGET(child->data) == item) return count;
810 count++;
811 child = child->next;
812 }
813 }
814 return -1;
815 }
816
817 #if wxUSE_TOOLTIPS
818 void wxListBox::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
819 {
820 GList *child = m_list->children;
821 while (child)
822 {
823 gtk_tooltips_set_tip( tips, GTK_WIDGET( child->data ), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
824 child = child->next;
825 }
826 }
827 #endif // wxUSE_TOOLTIPS
828
829 void wxListBox::GtkDisableEvents()
830 {
831 GList *child = m_list->children;
832 while (child)
833 {
834 gtk_signal_disconnect_by_func( GTK_OBJECT(child->data),
835 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
836
837 if (HasFlag(wxLB_MULTIPLE))
838 gtk_signal_disconnect_by_func( GTK_OBJECT(child->data),
839 GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback), (gpointer)this );
840
841 child = child->next;
842 }
843 }
844
845 void wxListBox::GtkEnableEvents()
846 {
847 GList *child = m_list->children;
848 while (child)
849 {
850 gtk_signal_connect( GTK_OBJECT(child->data), "select",
851 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
852
853 if (HasFlag(wxLB_MULTIPLE))
854 gtk_signal_connect( GTK_OBJECT(child->data), "deselect",
855 GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback), (gpointer)this );
856
857 child = child->next;
858 }
859 }
860
861 GtkWidget *wxListBox::GetConnectWidget()
862 {
863 return GTK_WIDGET(m_list);
864 }
865
866 bool wxListBox::IsOwnGtkWindow( GdkWindow *window )
867 {
868 if (wxWindow::IsOwnGtkWindow( window )) return TRUE;
869
870 GList *child = m_list->children;
871 while (child)
872 {
873 GtkWidget *bin = GTK_WIDGET( child->data );
874 if (bin->window == window) return TRUE;
875 child = child->next;
876 }
877
878 return FALSE;
879 }
880
881 void wxListBox::ApplyWidgetStyle()
882 {
883 SetWidgetStyle();
884
885 if (m_backgroundColour.Ok())
886 {
887 GdkWindow *window = GTK_WIDGET(m_list)->window;
888 if ( window )
889 {
890 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
891 gdk_window_set_background( window, m_backgroundColour.GetColor() );
892 gdk_window_clear( window );
893 }
894 }
895
896 GList *child = m_list->children;
897 while (child)
898 {
899 gtk_widget_set_style( GTK_WIDGET(child->data), m_widgetStyle );
900
901 GtkBin *bin = GTK_BIN( child->data );
902 GtkWidget *label = GTK_WIDGET( bin->child );
903 gtk_widget_set_style( label, m_widgetStyle );
904
905 child = child->next;
906 }
907 }
908
909 void wxListBox::OnInternalIdle()
910 {
911 wxCursor cursor = m_cursor;
912 if (g_globalCursor.Ok()) cursor = g_globalCursor;
913
914 if (GTK_WIDGET(m_list)->window && cursor.Ok())
915 {
916 /* I now set the cursor the anew in every OnInternalIdle call
917 as setting the cursor in a parent window also effects the
918 windows above so that checking for the current cursor is
919 not possible. */
920
921 gdk_window_set_cursor( GTK_WIDGET(m_list)->window, cursor.GetCursor() );
922
923 GList *child = m_list->children;
924 while (child)
925 {
926 GtkBin *bin = GTK_BIN( child->data );
927 GtkWidget *label = GTK_WIDGET( bin->child );
928
929 if (!label->window)
930 break;
931 else
932 gdk_window_set_cursor( label->window, cursor.GetCursor() );
933
934 child = child->next;
935 }
936 }
937
938 UpdateWindowUI();
939 }
940
941 #endif