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