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