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