]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/listbox.cpp
fix for pageup 'blind spot'
[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 #ifdef __VMS__
30 #define gtk_scrolled_window_add_with_viewport gtk_scrolled_window_add_with_vi
31 #define gtk_container_set_focus_vadjustment gtk_container_set_focus_vadjust
32 #define gtk_scrolled_window_get_vadjustment gtk_scrolled_window_get_vadjust
33 #endif
34 # include <gdk/gdk.h>
35 #include <gtk/gtk.h>
36 #include <gdk/gdkkeysyms.h>
37
38 //-----------------------------------------------------------------------------
39 // idle system
40 //-----------------------------------------------------------------------------
41
42 extern void wxapp_install_idle_handler();
43 extern bool g_isIdle;
44
45 //-------------------------------------------------------------------------
46 // conditional compilation
47 //-------------------------------------------------------------------------
48
49 #if (GTK_MINOR_VERSION > 0)
50 #define NEW_GTK_SCROLL_CODE
51 #endif
52
53 //-----------------------------------------------------------------------------
54 // private functions
55 //-----------------------------------------------------------------------------
56
57 #if wxUSE_CHECKLISTBOX
58
59 #define CHECKBOX_STRING "[-] "
60
61 // checklistboxes have "[±] " prepended to their lables, this macro removes it
62 // (NB: 4 below is the length of CHECKBOX_STRING above)
63 //
64 // the argument to it is a "const char *" pointer
65 #define GET_REAL_LABEL(label) ((m_hasCheckBoxes)?(label)+4 : (label))
66
67 #else // !wxUSE_CHECKLISTBOX
68
69 #define GET_REAL_LABEL(label) (label)
70
71 #endif // wxUSE_CHECKLISTBOX
72
73 //-----------------------------------------------------------------------------
74 // data
75 //-----------------------------------------------------------------------------
76
77 extern bool g_blockEventsOnDrag;
78 extern bool g_blockEventsOnScroll;
79 extern wxCursor g_globalCursor;
80
81 static bool g_hasDoubleClicked = FALSE;
82
83 //-----------------------------------------------------------------------------
84 // "button_release_event"
85 //-----------------------------------------------------------------------------
86
87 /* we would normally emit a wxEVT_COMMAND_LISTBOX_DOUBLECLICKED event once
88 a GDK_2BUTTON_PRESS occurs, but this has the particular problem of the
89 listbox keeping the focus until it receives a GDK_BUTTON_RELEASE event.
90 this can lead to race conditions so that we emit the dclick event
91 after the GDK_BUTTON_RELEASE event after the GDK_2BUTTON_PRESS event */
92
93 static gint
94 gtk_listbox_button_release_callback( GtkWidget * WXUNUSED(widget),
95 GdkEventButton * WXUNUSED(gdk_event),
96 wxListBox *listbox )
97 {
98 if (g_isIdle) wxapp_install_idle_handler();
99
100 if (g_blockEventsOnDrag) return FALSE;
101 if (g_blockEventsOnScroll) return FALSE;
102
103 if (!listbox->m_hasVMT) return FALSE;
104
105 if (!g_hasDoubleClicked) return FALSE;
106
107 wxCommandEvent event( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, listbox->GetId() );
108 event.SetEventObject( listbox );
109
110 wxArrayInt aSelections;
111 int n, count = listbox->GetSelections(aSelections);
112 if ( count > 0 )
113 {
114 n = aSelections[0];
115 if ( listbox->HasClientObjectData() )
116 event.SetClientObject( listbox->GetClientObject(n) );
117 else if ( listbox->HasClientUntypedData() )
118 event.SetClientData( listbox->GetClientData(n) );
119 event.SetString( listbox->GetString(n) );
120 }
121 else
122 {
123 n = -1;
124 }
125
126 event.m_commandInt = n;
127
128 listbox->GetEventHandler()->ProcessEvent( event );
129
130 return FALSE;
131 }
132
133 //-----------------------------------------------------------------------------
134 // "button_press_event"
135 //-----------------------------------------------------------------------------
136
137 static gint
138 gtk_listbox_button_press_callback( GtkWidget *widget,
139 GdkEventButton *gdk_event,
140 wxListBox *listbox )
141 {
142 if (g_isIdle) wxapp_install_idle_handler();
143
144 if (g_blockEventsOnDrag) return FALSE;
145 if (g_blockEventsOnScroll) return FALSE;
146
147 if (!listbox->m_hasVMT) return FALSE;
148
149 int sel = listbox->GtkGetIndex( widget );
150
151 #if wxUSE_CHECKLISTBOX
152 if ((listbox->m_hasCheckBoxes) && (gdk_event->x < 15) && (gdk_event->type != GDK_2BUTTON_PRESS))
153 {
154 wxCheckListBox *clb = (wxCheckListBox *)listbox;
155
156 clb->Check( sel, !clb->IsChecked(sel) );
157
158 wxCommandEvent event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, listbox->GetId() );
159 event.SetEventObject( listbox );
160 event.SetInt( sel );
161 listbox->GetEventHandler()->ProcessEvent( event );
162 }
163 #endif // wxUSE_CHECKLISTBOX
164
165 /* emit wxEVT_COMMAND_LISTBOX_DOUBLECLICKED later */
166 g_hasDoubleClicked = (gdk_event->type == GDK_2BUTTON_PRESS);
167
168 return FALSE;
169 }
170
171 //-----------------------------------------------------------------------------
172 // "key_press_event"
173 //-----------------------------------------------------------------------------
174
175 static gint
176 gtk_listbox_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxListBox *listbox )
177 {
178 if (g_isIdle)
179 wxapp_install_idle_handler();
180
181 if (g_blockEventsOnDrag)
182 return FALSE;
183
184 bool ret = FALSE;
185
186 if ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab))
187 {
188 wxNavigationKeyEvent new_event;
189 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
190 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
191 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
192 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
193 new_event.SetCurrentFocus( listbox );
194 ret = listbox->GetEventHandler()->ProcessEvent( new_event );
195 }
196
197 #if wxUSE_CHECKLISTBOX
198 if ((gdk_event->keyval == ' ') && (listbox->m_hasCheckBoxes) && (!ret))
199 {
200 int sel = listbox->GtkGetIndex( widget );
201
202 wxCheckListBox *clb = (wxCheckListBox *)listbox;
203
204 clb->Check( sel, !clb->IsChecked(sel) );
205
206 wxCommandEvent new_event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, listbox->GetId() );
207 new_event.SetEventObject( listbox );
208 new_event.SetInt( sel );
209 ret = listbox->GetEventHandler()->ProcessEvent( new_event );
210 }
211 #endif // wxUSE_CHECKLISTBOX
212
213 if (ret)
214 {
215 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
216 return TRUE;
217 }
218
219 return FALSE;
220 }
221
222 //-----------------------------------------------------------------------------
223 // "select" and "deselect"
224 //-----------------------------------------------------------------------------
225
226 static void gtk_listitem_select_callback( GtkWidget *WXUNUSED(widget), wxListBox *listbox );
227
228 static void gtk_listitem_deselect_callback( GtkWidget *widget, wxListBox *listbox )
229 {
230 gtk_listitem_select_callback( widget, listbox );
231 }
232
233 static void gtk_listitem_select_callback( GtkWidget *WXUNUSED(widget), wxListBox *listbox )
234 {
235 if (g_isIdle) wxapp_install_idle_handler();
236
237 if (!listbox->m_hasVMT) return;
238 if (g_blockEventsOnDrag) return;
239
240 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, listbox->GetId() );
241 event.SetEventObject( listbox );
242
243 wxArrayInt aSelections;
244 int n, count = listbox->GetSelections(aSelections);
245 if ( count > 0 )
246 {
247 n = aSelections[0];
248 if ( listbox->HasClientObjectData() )
249 event.SetClientObject( listbox->GetClientObject(n) );
250 else if ( listbox->HasClientUntypedData() )
251 event.SetClientData( listbox->GetClientData(n) );
252 event.SetString( listbox->GetString(n) );
253 }
254 else
255 {
256 n = -1;
257 }
258
259 event.m_commandInt = n;
260
261 listbox->GetEventHandler()->AddPendingEvent( event );
262 // listbox->GetEventHandler()->ProcessEvent( event );
263 }
264
265 //-----------------------------------------------------------------------------
266 // wxListBox
267 //-----------------------------------------------------------------------------
268
269 IMPLEMENT_DYNAMIC_CLASS(wxListBox,wxControl)
270
271 // ----------------------------------------------------------------------------
272 // construction
273 // ----------------------------------------------------------------------------
274
275 wxListBox::wxListBox()
276 {
277 m_list = (GtkList *) NULL;
278 #if wxUSE_CHECKLISTBOX
279 m_hasCheckBoxes = FALSE;
280 #endif // wxUSE_CHECKLISTBOX
281 }
282
283 bool wxListBox::Create( wxWindow *parent, wxWindowID id,
284 const wxPoint &pos, const wxSize &size,
285 int n, const wxString choices[],
286 long style, const wxValidator& validator,
287 const wxString &name )
288 {
289 m_needParent = TRUE;
290 m_acceptsFocus = TRUE;
291
292 if (!PreCreation( parent, pos, size ) ||
293 !CreateBase( parent, id, pos, size, style, validator, name ))
294 {
295 wxFAIL_MSG( wxT("wxListBox creation failed") );
296 return FALSE;
297 }
298
299 m_widget = gtk_scrolled_window_new( (GtkAdjustment*) NULL, (GtkAdjustment*) NULL );
300 if (style & wxLB_ALWAYS_SB)
301 {
302 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
303 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS );
304 }
305 else
306 {
307 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
308 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
309 }
310
311 m_list = GTK_LIST( gtk_list_new() );
312
313 GtkSelectionMode mode = GTK_SELECTION_BROWSE;
314 if (style & wxLB_MULTIPLE)
315 mode = GTK_SELECTION_MULTIPLE;
316 else if (style & wxLB_EXTENDED)
317 mode = GTK_SELECTION_EXTENDED;
318
319 gtk_list_set_selection_mode( GTK_LIST(m_list), mode );
320
321 #ifdef NEW_GTK_SCROLL_CODE
322 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(m_widget), GTK_WIDGET(m_list) );
323 #else
324 gtk_container_add( GTK_CONTAINER(m_widget), GTK_WIDGET(m_list) );
325 #endif
326
327 /* make list scroll when moving the focus down using cursor keys */
328 gtk_container_set_focus_vadjustment(
329 GTK_CONTAINER(m_list),
330 gtk_scrolled_window_get_vadjustment(
331 GTK_SCROLLED_WINDOW(m_widget)));
332
333 gtk_widget_show( GTK_WIDGET(m_list) );
334
335 SetSizeOrDefault( size );
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_LISTBOX ) );
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
765 wxCHECK_MSG( target, FALSE, wxT("invalid listbox index") );
766
767 return (GTK_WIDGET(target->data)->state == GTK_STATE_SELECTED) ;
768 }
769
770 void wxListBox::SetSelection( int n, bool select )
771 {
772 wxCHECK_RET( m_list != NULL, wxT("invalid listbox") );
773
774 GtkDisableEvents();
775
776 if (select)
777 gtk_list_select_item( m_list, n );
778 else
779 gtk_list_unselect_item( m_list, n );
780
781 GtkEnableEvents();
782 }
783
784 void wxListBox::DoSetFirstItem( int WXUNUSED(n) )
785 {
786 wxFAIL_MSG(wxT("wxListBox::SetFirstItem not implemented"));
787 }
788
789 // ----------------------------------------------------------------------------
790 // helpers
791 // ----------------------------------------------------------------------------
792
793 int wxListBox::GtkGetIndex( GtkWidget *item ) const
794 {
795 if (item)
796 {
797 GList *child = m_list->children;
798 int count = 0;
799 while (child)
800 {
801 if (GTK_WIDGET(child->data) == item) return count;
802 count++;
803 child = child->next;
804 }
805 }
806 return -1;
807 }
808
809 #if wxUSE_TOOLTIPS
810 void wxListBox::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
811 {
812 GList *child = m_list->children;
813 while (child)
814 {
815 gtk_tooltips_set_tip( tips, GTK_WIDGET( child->data ), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
816 child = child->next;
817 }
818 }
819 #endif // wxUSE_TOOLTIPS
820
821 void wxListBox::GtkDisableEvents()
822 {
823 GList *child = m_list->children;
824 while (child)
825 {
826 gtk_signal_disconnect_by_func( GTK_OBJECT(child->data),
827 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
828
829 if (HasFlag(wxLB_MULTIPLE))
830 gtk_signal_disconnect_by_func( GTK_OBJECT(child->data),
831 GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback), (gpointer)this );
832
833 child = child->next;
834 }
835 }
836
837 void wxListBox::GtkEnableEvents()
838 {
839 GList *child = m_list->children;
840 while (child)
841 {
842 gtk_signal_connect( GTK_OBJECT(child->data), "select",
843 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
844
845 if (HasFlag(wxLB_MULTIPLE))
846 gtk_signal_connect( GTK_OBJECT(child->data), "deselect",
847 GTK_SIGNAL_FUNC(gtk_listitem_deselect_callback), (gpointer)this );
848
849 child = child->next;
850 }
851 }
852
853 GtkWidget *wxListBox::GetConnectWidget()
854 {
855 return GTK_WIDGET(m_list);
856 }
857
858 bool wxListBox::IsOwnGtkWindow( GdkWindow *window )
859 {
860 if (GTK_WIDGET(m_list)->window == window) return TRUE;
861
862 GList *child = m_list->children;
863 while (child)
864 {
865 GtkWidget *bin = GTK_WIDGET( child->data );
866 if (bin->window == window) return TRUE;
867 child = child->next;
868 }
869
870 return FALSE;
871 }
872
873 void wxListBox::ApplyWidgetStyle()
874 {
875 SetWidgetStyle();
876
877 if (m_backgroundColour.Ok())
878 {
879 GdkWindow *window = GTK_WIDGET(m_list)->window;
880 if ( window )
881 {
882 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
883 gdk_window_set_background( window, m_backgroundColour.GetColor() );
884 gdk_window_clear( window );
885 }
886 }
887
888 GList *child = m_list->children;
889 while (child)
890 {
891 gtk_widget_set_style( GTK_WIDGET(child->data), m_widgetStyle );
892
893 GtkBin *bin = GTK_BIN( child->data );
894 GtkWidget *label = GTK_WIDGET( bin->child );
895 gtk_widget_set_style( label, m_widgetStyle );
896
897 child = child->next;
898 }
899 }
900
901 void wxListBox::OnInternalIdle()
902 {
903 wxCursor cursor = m_cursor;
904 if (g_globalCursor.Ok()) cursor = g_globalCursor;
905
906 if (GTK_WIDGET(m_list)->window && cursor.Ok())
907 {
908 /* I now set the cursor the anew in every OnInternalIdle call
909 as setting the cursor in a parent window also effects the
910 windows above so that checking for the current cursor is
911 not possible. */
912
913 gdk_window_set_cursor( GTK_WIDGET(m_list)->window, cursor.GetCursor() );
914
915 GList *child = m_list->children;
916 while (child)
917 {
918 GtkBin *bin = GTK_BIN( child->data );
919 GtkWidget *label = GTK_WIDGET( bin->child );
920
921 if (!label->window)
922 break;
923 else
924 gdk_window_set_cursor( label->window, cursor.GetCursor() );
925
926 child = child->next;
927 }
928 }
929
930 UpdateWindowUI();
931 }
932
933 wxSize wxListBox::DoGetBestSize() const
934 {
935 return wxSize(100, 110);
936 }
937
938 #endif