wxListBox now sends events using AddPendingEvent(),
[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()->AddPendingEvent( event );
257 // listbox->GetEventHandler()->ProcessEvent( event );
258 }
259
260 //-----------------------------------------------------------------------------
261 // wxListBox
262 //-----------------------------------------------------------------------------
263
264 IMPLEMENT_DYNAMIC_CLASS(wxListBox,wxControl)
265
266 // ----------------------------------------------------------------------------
267 // construction
268 // ----------------------------------------------------------------------------
269
270 wxListBox::wxListBox()
271 {
272 m_list = (GtkList *) NULL;
273 #if wxUSE_CHECKLISTBOX
274 m_hasCheckBoxes = FALSE;
275 #endif // wxUSE_CHECKLISTBOX
276 }
277
278 bool wxListBox::Create( wxWindow *parent, wxWindowID id,
279 const wxPoint &pos, const wxSize &size,
280 int n, const wxString choices[],
281 long style, const wxValidator& validator,
282 const wxString &name )
283 {
284 m_needParent = TRUE;
285 m_acceptsFocus = TRUE;
286
287 if (!PreCreation( parent, pos, size ) ||
288 !CreateBase( parent, id, pos, size, style, validator, name ))
289 {
290 wxFAIL_MSG( wxT("wxListBox creation failed") );
291 return FALSE;
292 }
293
294 m_widget = gtk_scrolled_window_new( (GtkAdjustment*) NULL, (GtkAdjustment*) NULL );
295 if (style & wxLB_ALWAYS_SB)
296 {
297 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
298 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS );
299 }
300 else
301 {
302 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
303 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
304 }
305
306 m_list = GTK_LIST( gtk_list_new() );
307
308 GtkSelectionMode mode = GTK_SELECTION_BROWSE;
309 if (style & wxLB_MULTIPLE)
310 mode = GTK_SELECTION_MULTIPLE;
311 else if (style & wxLB_EXTENDED)
312 mode = GTK_SELECTION_EXTENDED;
313
314 gtk_list_set_selection_mode( GTK_LIST(m_list), mode );
315
316 #ifdef NEW_GTK_SCROLL_CODE
317 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(m_widget), GTK_WIDGET(m_list) );
318 #else
319 gtk_container_add( GTK_CONTAINER(m_widget), GTK_WIDGET(m_list) );
320 #endif
321
322 /* make list scroll when moving the focus down using cursor keys */
323 gtk_container_set_focus_vadjustment(
324 GTK_CONTAINER(m_list),
325 gtk_scrolled_window_get_vadjustment(
326 GTK_SCROLLED_WINDOW(m_widget)));
327
328 gtk_widget_show( GTK_WIDGET(m_list) );
329
330 wxSize newSize = size;
331 if (newSize.x == -1)
332 newSize.x = 100;
333 if (newSize.y == -1)
334 newSize.y = 110;
335 SetSize( newSize.x, newSize.y );
336
337 if ( style & wxLB_SORT )
338 {
339 // this will change DoAppend() behaviour
340 m_strings = new wxSortedArrayString;
341 }
342 else
343 {
344 m_strings = (wxSortedArrayString *)NULL;
345 }
346
347 for (int i = 0; i < n; i++)
348 {
349 // add one by one
350 DoAppend(choices[i]);
351 }
352
353 m_parent->DoAddChild( this );
354
355 PostCreation();
356
357 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOW ) );
358 SetForegroundColour( parent->GetForegroundColour() );
359 SetFont( parent->GetFont() );
360
361 Show( TRUE );
362
363 return TRUE;
364 }
365
366 wxListBox::~wxListBox()
367 {
368 Clear();
369 }
370
371 void wxListBox::DoInsertItems(const wxArrayString& items, int pos)
372 {
373 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
374
375 // VZ: notice that InsertItems knows nothing about sorting, so calling it
376 // from outside (and not from our own Append) is likely to break
377 // everything
378
379 // code elsewhere supposes we have as many items in m_clientList as items
380 // in the listbox
381 wxASSERT_MSG( m_clientList.GetCount() == (size_t)GetCount(),
382 wxT("bug in client data management") );
383
384 GList *children = m_list->children;
385 int length = g_list_length(children);
386
387 wxCHECK_RET( pos <= length, wxT("invalid index in wxListBox::InsertItems") );
388
389 size_t nItems = items.GetCount();
390
391 if (pos == length)
392 {
393 for ( size_t n = 0; n < nItems; n++ )
394 {
395 GtkAddItem( items[n] );
396
397 m_clientList.Append((wxObject *)NULL);
398 }
399 }
400 else
401 {
402 wxNode *node = m_clientList.Nth( pos );
403 for ( size_t n = 0; n < nItems; n++ )
404 {
405 GtkAddItem( items[n], pos+n );
406
407 m_clientList.Insert( node, (wxObject *)NULL );
408 }
409 }
410
411 wxASSERT_MSG( m_clientList.GetCount() == (size_t)GetCount(),
412 wxT("bug in client data management") );
413 }
414
415 int wxListBox::DoAppend( const wxString& item )
416 {
417 if (m_strings)
418 {
419 // need to determine the index
420 int index = m_strings->Add( item );
421
422 // only if not at the end anyway
423 if (index != GetCount())
424 {
425 GtkAddItem( item, index );
426
427 wxNode *node = m_clientList.Nth( index );
428 m_clientList.Insert( node, (wxObject *)NULL );
429
430 return index;
431 }
432 }
433
434 GtkAddItem(item);
435
436 m_clientList.Append((wxObject *)NULL);
437
438 return GetCount() - 1;
439 }
440
441 void wxListBox::GtkAddItem( const wxString &item, int pos )
442 {
443 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
444
445 GtkWidget *list_item;
446
447 wxString label(item);
448 #if wxUSE_CHECKLISTBOX
449 if (m_hasCheckBoxes)
450 {
451 label.Prepend(CHECKBOX_STRING);
452 }
453 #endif // wxUSE_CHECKLISTBOX
454
455 list_item = gtk_list_item_new_with_label( label.mbc_str() );
456
457 GList *gitem_list = g_list_alloc ();
458 gitem_list->data = list_item;
459
460 if (pos == -1)
461 gtk_list_append_items( GTK_LIST (m_list), gitem_list );
462 else
463 gtk_list_insert_items( GTK_LIST (m_list), gitem_list, pos );
464
465 gtk_signal_connect( GTK_OBJECT(list_item), "select",
466 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
467
468 if (HasFlag(wxLB_MULTIPLE))
469 gtk_signal_connect( GTK_OBJECT(list_item), "deselect",
470 GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback), (gpointer)this );
471
472 gtk_signal_connect( GTK_OBJECT(list_item),
473 "button_press_event",
474 (GtkSignalFunc)gtk_listbox_button_press_callback,
475 (gpointer) this );
476
477 gtk_signal_connect_after( GTK_OBJECT(list_item),
478 "button_release_event",
479 (GtkSignalFunc)gtk_listbox_button_release_callback,
480 (gpointer) this );
481
482 gtk_signal_connect( GTK_OBJECT(list_item),
483 "key_press_event",
484 (GtkSignalFunc)gtk_listbox_key_press_callback,
485 (gpointer)this );
486
487 ConnectWidget( list_item );
488
489 gtk_widget_show( list_item );
490
491 if (GTK_WIDGET_REALIZED(m_widget))
492 {
493 gtk_widget_realize( list_item );
494 gtk_widget_realize( GTK_BIN(list_item)->child );
495
496 // Apply current widget style to the new list_item
497 if (m_widgetStyle)
498 {
499 gtk_widget_set_style( GTK_WIDGET( list_item ), m_widgetStyle );
500 GtkBin *bin = GTK_BIN( list_item );
501 GtkWidget *label = GTK_WIDGET( bin->child );
502 gtk_widget_set_style( label, m_widgetStyle );
503 }
504
505 #if wxUSE_TOOLTIPS
506 if (m_tooltip) m_tooltip->Apply( this );
507 #endif
508 }
509 }
510
511 void wxListBox::DoSetItems( const wxArrayString& items,
512 void **clientData)
513 {
514 Clear();
515
516 DoInsertItems(items, 0);
517
518 if ( clientData )
519 {
520 size_t count = items.GetCount();
521 for ( size_t n = 0; n < count; n++ )
522 {
523 SetClientData(n, clientData[n]);
524 }
525 }
526 }
527
528 // ----------------------------------------------------------------------------
529 // client data
530 // ----------------------------------------------------------------------------
531
532 void wxListBox::DoSetItemClientData( int n, void* clientData )
533 {
534 wxCHECK_RET( m_widget != NULL, wxT("invalid listbox control") );
535
536 wxNode *node = m_clientList.Nth( n );
537 wxCHECK_RET( node, wxT("invalid index in wxListBox::DoSetItemClientData") );
538
539 node->SetData( (wxObject*) clientData );
540 }
541
542 void* wxListBox::DoGetItemClientData( int n ) const
543 {
544 wxCHECK_MSG( m_widget != NULL, NULL, wxT("invalid listbox control") );
545
546 wxNode *node = m_clientList.Nth( n );
547 wxCHECK_MSG( node, NULL, wxT("invalid index in wxListBox::DoGetItemClientData") );
548
549 return node->Data();
550 }
551
552 void wxListBox::DoSetItemClientObject( int n, wxClientData* clientData )
553 {
554 wxCHECK_RET( m_widget != NULL, wxT("invalid listbox control") );
555
556 wxNode *node = m_clientList.Nth( n );
557 wxCHECK_RET( node, wxT("invalid index in wxListBox::DoSetItemClientObject") );
558
559 wxClientData *cd = (wxClientData*) node->Data();
560 delete cd;
561
562 node->SetData( (wxObject*) clientData );
563 }
564
565 wxClientData* wxListBox::DoGetItemClientObject( int n ) const
566 {
567 wxCHECK_MSG( m_widget != NULL, (wxClientData*) NULL, wxT("invalid listbox control") );
568
569 wxNode *node = m_clientList.Nth( n );
570 wxCHECK_MSG( node, (wxClientData *)NULL,
571 wxT("invalid index in wxListBox::DoGetItemClientObject") );
572
573 return (wxClientData*) node->Data();
574 }
575
576 void wxListBox::Clear()
577 {
578 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
579
580 gtk_list_clear_items( m_list, 0, Number() );
581
582 if ( HasClientObjectData() )
583 {
584 // destroy the data (due to Robert's idea of using wxList<wxObject>
585 // and not wxList<wxClientData> we can't just say
586 // m_clientList.DeleteContents(TRUE) - this would crash!
587 wxNode *node = m_clientList.First();
588 while ( node )
589 {
590 delete (wxClientData *)node->Data();
591 node = node->Next();
592 }
593 }
594 m_clientList.Clear();
595
596 if ( m_strings )
597 m_strings->Clear();
598 }
599
600 void wxListBox::Delete( int n )
601 {
602 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
603
604 GList *child = g_list_nth( m_list->children, n );
605
606 wxCHECK_RET( child, wxT("wrong listbox index") );
607
608 GList *list = g_list_append( (GList*) NULL, child->data );
609 gtk_list_remove_items( m_list, list );
610 g_list_free( list );
611
612 wxNode *node = m_clientList.Nth( n );
613 if ( node )
614 {
615 if ( m_clientDataItemsType == ClientData_Object )
616 {
617 wxClientData *cd = (wxClientData*)node->Data();
618 delete cd;
619 }
620
621 m_clientList.DeleteNode( node );
622 }
623
624 if ( m_strings )
625 m_strings->Remove(n);
626 }
627
628 // ----------------------------------------------------------------------------
629 // string list access
630 // ----------------------------------------------------------------------------
631
632 void wxListBox::SetString( int n, const wxString &string )
633 {
634 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
635
636 GList *child = g_list_nth( m_list->children, n );
637 if (child)
638 {
639 GtkBin *bin = GTK_BIN( child->data );
640 GtkLabel *label = GTK_LABEL( bin->child );
641
642 wxString str;
643 #if wxUSE_CHECKLISTBOX
644 if (m_hasCheckBoxes)
645 str += CHECKBOX_STRING;
646 #endif // wxUSE_CHECKLISTBOX
647 str += string;
648
649 gtk_label_set( label, str.mbc_str() );
650 }
651 else
652 {
653 wxFAIL_MSG(wxT("wrong listbox index"));
654 }
655 }
656
657 wxString wxListBox::GetString( int n ) const
658 {
659 wxCHECK_MSG( m_list != NULL, wxT(""), wxT("invalid listbox") );
660
661 GList *child = g_list_nth( m_list->children, n );
662 if (child)
663 {
664 GtkBin *bin = GTK_BIN( child->data );
665 GtkLabel *label = GTK_LABEL( bin->child );
666
667 wxString str = wxString(GET_REAL_LABEL(label->label),*wxConvCurrent);
668
669 return str;
670 }
671
672 wxFAIL_MSG(wxT("wrong listbox index"));
673
674 return wxT("");
675 }
676
677 int wxListBox::GetCount() const
678 {
679 wxCHECK_MSG( m_list != NULL, -1, wxT("invalid listbox") );
680
681 GList *children = m_list->children;
682 return g_list_length(children);
683 }
684
685 int wxListBox::FindString( const wxString &item ) const
686 {
687 wxCHECK_MSG( m_list != NULL, -1, wxT("invalid listbox") );
688
689 GList *child = m_list->children;
690 int count = 0;
691 while (child)
692 {
693 GtkBin *bin = GTK_BIN( child->data );
694 GtkLabel *label = GTK_LABEL( bin->child );
695
696 wxString str = wxString(GET_REAL_LABEL(label->label),*wxConvCurrent);
697
698 if (str == item)
699 return count;
700
701 count++;
702 child = child->next;
703 }
704
705 // it's not an error if the string is not found -> no wxCHECK
706
707 return wxNOT_FOUND;
708 }
709
710 // ----------------------------------------------------------------------------
711 // selection
712 // ----------------------------------------------------------------------------
713
714 int wxListBox::GetSelection() const
715 {
716 wxCHECK_MSG( m_list != NULL, -1, wxT("invalid listbox") );
717
718 GList *child = m_list->children;
719 int count = 0;
720 while (child)
721 {
722 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED) return count;
723 count++;
724 child = child->next;
725 }
726 return -1;
727 }
728
729 int wxListBox::GetSelections( wxArrayInt& aSelections ) const
730 {
731 wxCHECK_MSG( m_list != NULL, -1, wxT("invalid listbox") );
732
733 // get the number of selected items first
734 GList *child = m_list->children;
735 int count = 0;
736 for (child = m_list->children; child != NULL; child = child->next)
737 {
738 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED)
739 count++;
740 }
741
742 aSelections.Empty();
743
744 if (count > 0)
745 {
746 // now fill the list
747 aSelections.Alloc(count); // optimization attempt
748 int i = 0;
749 for (child = m_list->children; child != NULL; child = child->next, i++)
750 {
751 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED)
752 aSelections.Add(i);
753 }
754 }
755
756 return count;
757 }
758
759 bool wxListBox::IsSelected( int n ) const
760 {
761 wxCHECK_MSG( m_list != NULL, FALSE, wxT("invalid listbox") );
762
763 GList *target = g_list_nth( m_list->children, n );
764 if (target)
765 {
766 GList *child = m_list->selection;
767 while (child)
768 {
769 if (child->data == target->data) return TRUE;
770 child = child->next;
771 }
772 }
773
774 wxFAIL_MSG(wxT("wrong listbox index"));
775
776 return FALSE;
777 }
778
779 void wxListBox::SetSelection( int n, bool select )
780 {
781 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
782
783 GtkDisableEvents();
784
785 if (select)
786 gtk_list_select_item( m_list, n );
787 else
788 gtk_list_unselect_item( m_list, n );
789
790 GtkEnableEvents();
791 }
792
793 void wxListBox::DoSetFirstItem( int WXUNUSED(n) )
794 {
795 wxFAIL_MSG(wxT("wxListBox::SetFirstItem not implemented"));
796 }
797
798 // ----------------------------------------------------------------------------
799 // helpers
800 // ----------------------------------------------------------------------------
801
802 int wxListBox::GtkGetIndex( GtkWidget *item ) const
803 {
804 if (item)
805 {
806 GList *child = m_list->children;
807 int count = 0;
808 while (child)
809 {
810 if (GTK_WIDGET(child->data) == item) return count;
811 count++;
812 child = child->next;
813 }
814 }
815 return -1;
816 }
817
818 #if wxUSE_TOOLTIPS
819 void wxListBox::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
820 {
821 GList *child = m_list->children;
822 while (child)
823 {
824 gtk_tooltips_set_tip( tips, GTK_WIDGET( child->data ), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
825 child = child->next;
826 }
827 }
828 #endif // wxUSE_TOOLTIPS
829
830 void wxListBox::GtkDisableEvents()
831 {
832 GList *child = m_list->children;
833 while (child)
834 {
835 gtk_signal_disconnect_by_func( GTK_OBJECT(child->data),
836 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
837
838 if (HasFlag(wxLB_MULTIPLE))
839 gtk_signal_disconnect_by_func( GTK_OBJECT(child->data),
840 GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback), (gpointer)this );
841
842 child = child->next;
843 }
844 }
845
846 void wxListBox::GtkEnableEvents()
847 {
848 GList *child = m_list->children;
849 while (child)
850 {
851 gtk_signal_connect( GTK_OBJECT(child->data), "select",
852 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
853
854 if (HasFlag(wxLB_MULTIPLE))
855 gtk_signal_connect( GTK_OBJECT(child->data), "deselect",
856 GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback), (gpointer)this );
857
858 child = child->next;
859 }
860 }
861
862 GtkWidget *wxListBox::GetConnectWidget()
863 {
864 return GTK_WIDGET(m_list);
865 }
866
867 bool wxListBox::IsOwnGtkWindow( GdkWindow *window )
868 {
869 if (wxWindow::IsOwnGtkWindow( window )) return TRUE;
870
871 GList *child = m_list->children;
872 while (child)
873 {
874 GtkWidget *bin = GTK_WIDGET( child->data );
875 if (bin->window == window) return TRUE;
876 child = child->next;
877 }
878
879 return FALSE;
880 }
881
882 void wxListBox::ApplyWidgetStyle()
883 {
884 SetWidgetStyle();
885
886 if (m_backgroundColour.Ok())
887 {
888 GdkWindow *window = GTK_WIDGET(m_list)->window;
889 if ( window )
890 {
891 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
892 gdk_window_set_background( window, m_backgroundColour.GetColor() );
893 gdk_window_clear( window );
894 }
895 }
896
897 GList *child = m_list->children;
898 while (child)
899 {
900 gtk_widget_set_style( GTK_WIDGET(child->data), m_widgetStyle );
901
902 GtkBin *bin = GTK_BIN( child->data );
903 GtkWidget *label = GTK_WIDGET( bin->child );
904 gtk_widget_set_style( label, m_widgetStyle );
905
906 child = child->next;
907 }
908 }
909
910 void wxListBox::OnInternalIdle()
911 {
912 wxCursor cursor = m_cursor;
913 if (g_globalCursor.Ok()) cursor = g_globalCursor;
914
915 if (GTK_WIDGET(m_list)->window && cursor.Ok())
916 {
917 /* I now set the cursor the anew in every OnInternalIdle call
918 as setting the cursor in a parent window also effects the
919 windows above so that checking for the current cursor is
920 not possible. */
921
922 gdk_window_set_cursor( GTK_WIDGET(m_list)->window, cursor.GetCursor() );
923
924 GList *child = m_list->children;
925 while (child)
926 {
927 GtkBin *bin = GTK_BIN( child->data );
928 GtkWidget *label = GTK_WIDGET( bin->child );
929
930 if (!label->window)
931 break;
932 else
933 gdk_window_set_cursor( label->window, cursor.GetCursor() );
934
935 child = child->next;
936 }
937 }
938
939 UpdateWindowUI();
940 }
941
942 #endif