]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk1/listbox.cpp
* First draft on wxStreamBuffer, wxStream* will follow.
[wxWidgets.git] / src / gtk1 / listbox.cpp
... / ...
CommitLineData
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/dynarray.h"
16#include "wx/listbox.h"
17#include "wx/utils.h"
18#include "wx/intl.h"
19#include "wx/checklst.h"
20
21#if wxUSE_DRAG_AND_DROP
22#include "wx/dnd.h"
23#endif
24
25#include "gdk/gdk.h"
26#include "gtk/gtk.h"
27
28//-------------------------------------------------------------------------
29// conditional compilation
30//-------------------------------------------------------------------------
31
32#if (GTK_MINOR_VERSION == 1)
33#if (GTK_MICRO_VERSION >= 5)
34#define NEW_GTK_SCROLL_CODE
35#endif
36#endif
37
38//-----------------------------------------------------------------------------
39// data
40//-----------------------------------------------------------------------------
41
42extern bool g_blockEventsOnDrag;
43extern bool g_blockEventsOnScroll;
44
45//-----------------------------------------------------------------------------
46// "button_press_event"
47//-----------------------------------------------------------------------------
48
49static gint
50gtk_listbox_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxListBox *listbox )
51{
52 if (g_blockEventsOnDrag) return FALSE;
53 if (g_blockEventsOnScroll) return FALSE;
54
55 if (!listbox->HasVMT()) return FALSE;
56
57 int sel = listbox->GetIndex( widget );
58
59 if ((listbox->m_hasCheckBoxes) && (gdk_event->x < 15) && (gdk_event->type != GDK_2BUTTON_PRESS))
60 {
61 wxCheckListBox *clb = (wxCheckListBox *)listbox;
62
63 clb->Check( sel, !clb->IsChecked(sel) );
64
65 wxCommandEvent event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, listbox->GetId() );
66 event.SetEventObject( listbox );
67 event.SetInt( sel );
68 listbox->GetEventHandler()->ProcessEvent( event );
69 }
70
71 if (gdk_event->type == GDK_2BUTTON_PRESS)
72 {
73 wxCommandEvent event( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, listbox->GetId() );
74 event.SetEventObject( listbox );
75 event.SetInt( sel );
76 listbox->GetEventHandler()->ProcessEvent( event );
77 }
78
79 return FALSE;
80}
81
82//-----------------------------------------------------------------------------
83// "key_press_event"
84//-----------------------------------------------------------------------------
85
86static gint
87gtk_listbox_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxListBox *listbox )
88{
89 if (g_blockEventsOnDrag) return FALSE;
90
91 if (!listbox->HasVMT()) return FALSE;
92
93 if (gdk_event->keyval != ' ') return FALSE;
94
95 int sel = listbox->GetIndex( widget );
96
97 wxCheckListBox *clb = (wxCheckListBox *)listbox;
98
99 clb->Check( sel, !clb->IsChecked(sel) );
100
101 wxCommandEvent event( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, listbox->GetId() );
102 event.SetEventObject( listbox );
103 event.SetInt( sel );
104 listbox->GetEventHandler()->ProcessEvent( event );
105
106 return FALSE;
107}
108
109//-----------------------------------------------------------------------------
110// "select" and "deselect"
111//-----------------------------------------------------------------------------
112
113static void gtk_listitem_select_callback( GtkWidget *WXUNUSED(widget), wxListBox *listbox )
114{
115 if (!listbox->HasVMT()) return;
116 if (g_blockEventsOnDrag) return;
117
118 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, listbox->GetId() );
119
120 wxArrayInt aSelections;
121 int count = listbox->GetSelections(aSelections);
122 if ( count > 0 )
123 {
124 event.m_commandInt = aSelections[0] ;
125 event.m_clientData = listbox->GetClientData( event.m_commandInt );
126 wxString str(listbox->GetString(event.m_commandInt));
127 if (str != "") event.m_commandString = copystring((char *)(const char *)str);
128 }
129 else
130 {
131 event.m_commandInt = -1 ;
132 event.m_commandString = copystring("") ;
133 }
134
135 event.SetEventObject( listbox );
136
137 listbox->GetEventHandler()->ProcessEvent( event );
138 if (event.m_commandString) delete[] event.m_commandString ;
139}
140
141//-----------------------------------------------------------------------------
142// wxListBox
143//-----------------------------------------------------------------------------
144
145IMPLEMENT_DYNAMIC_CLASS(wxListBox,wxControl)
146
147wxListBox::wxListBox()
148{
149 m_list = (GtkList *) NULL;
150 m_hasCheckBoxes = FALSE;
151}
152
153bool wxListBox::Create( wxWindow *parent, wxWindowID id,
154 const wxPoint &pos, const wxSize &size,
155 int n, const wxString choices[],
156 long style, const wxValidator& validator, const wxString &name )
157{
158 m_needParent = TRUE;
159 m_acceptsFocus = TRUE;
160
161 PreCreation( parent, id, pos, size, style, name );
162
163 SetValidator( validator );
164
165 m_widget = gtk_scrolled_window_new( (GtkAdjustment*) NULL, (GtkAdjustment*) NULL );
166 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
167 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
168
169 m_list = GTK_LIST( gtk_list_new() );
170
171 GtkSelectionMode mode = GTK_SELECTION_BROWSE;
172 if (style & wxLB_MULTIPLE)
173 mode = GTK_SELECTION_MULTIPLE;
174 else if (style & wxLB_EXTENDED)
175 mode = GTK_SELECTION_EXTENDED;
176
177 gtk_list_set_selection_mode( GTK_LIST(m_list), mode );
178
179#ifdef NEW_GTK_SCROLL_CODE
180 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(m_widget), GTK_WIDGET(m_list) );
181#else
182 gtk_container_add( GTK_CONTAINER(m_widget), GTK_WIDGET(m_list) );
183#endif
184
185#ifdef __WXDEBUG__
186 debug_focus_in( m_widget, "wxListBox::m_widget", name );
187
188 debug_focus_in( GTK_WIDGET(m_list), "wxListBox::m_list", name );
189
190 GtkScrolledWindow *s_window = GTK_SCROLLED_WINDOW(m_widget);
191
192 debug_focus_in( s_window->hscrollbar, "wxWindow::hsrcollbar", name );
193 debug_focus_in( s_window->vscrollbar, "wxWindow::vsrcollbar", name );
194
195#ifdef NEW_GTK_SCROLL_CODE
196 GtkViewport *viewport = GTK_VIEWPORT(s_window->child);
197#else
198 GtkViewport *viewport = GTK_VIEWPORT(s_window->viewport);
199#endif
200
201 debug_focus_in( GTK_WIDGET(viewport), "wxWindow::viewport", name );
202#endif
203
204 gtk_widget_show( GTK_WIDGET(m_list) );
205
206 wxSize newSize = size;
207 if (newSize.x == -1) newSize.x = 100;
208 if (newSize.y == -1) newSize.y = 110;
209 SetSize( newSize.x, newSize.y );
210
211 for (int i = 0; i < n; i++)
212 {
213 m_clientDataList.Append( (wxObject*) NULL );
214 m_clientObjectList.Append( (wxObject*) NULL );
215
216 GtkWidget *list_item;
217
218 if (m_hasCheckBoxes)
219 {
220 wxString str = "[-] ";
221 str += choices[i];
222 list_item = gtk_list_item_new_with_label( str );
223 }
224 else
225 {
226 list_item = gtk_list_item_new_with_label( choices[i] );
227 }
228
229#ifdef __WXDEBUG__
230 debug_focus_in( list_item, "wxListBox::list_item", name );
231#endif
232
233 gtk_container_add( GTK_CONTAINER(m_list), list_item );
234
235 gtk_signal_connect( GTK_OBJECT(list_item), "select",
236 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
237
238 if (style & wxLB_MULTIPLE)
239 gtk_signal_connect( GTK_OBJECT(list_item), "deselect",
240 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
241
242 gtk_signal_connect( GTK_OBJECT(list_item),
243 "button_press_event",
244 (GtkSignalFunc)gtk_listbox_button_press_callback,
245 (gpointer) this );
246
247 if (m_hasCheckBoxes)
248 {
249 gtk_signal_connect( GTK_OBJECT(list_item),
250 "key_press_event",
251 (GtkSignalFunc)gtk_listbox_key_press_callback,
252 (gpointer)this );
253 }
254
255 ConnectWidget( list_item );
256
257 gtk_widget_show( list_item );
258 }
259
260 m_parent->AddChild( this );
261
262 (m_parent->m_insertCallback)( m_parent, this );
263
264 PostCreation();
265
266 gtk_widget_realize( GTK_WIDGET(m_list) );
267
268 SetBackgroundColour( parent->GetBackgroundColour() );
269 SetForegroundColour( parent->GetForegroundColour() );
270
271 Show( TRUE );
272
273 return TRUE;
274}
275
276wxListBox::~wxListBox()
277{
278 Clear();
279}
280
281void wxListBox::AppendCommon( const wxString &item )
282{
283 wxCHECK_RET( m_list != NULL, "invalid listbox" );
284
285 GtkWidget *list_item;
286
287 if (m_hasCheckBoxes)
288 {
289 wxString str = "[-] ";
290 str += item;
291 list_item = gtk_list_item_new_with_label( str );
292 }
293 else
294 {
295 list_item = gtk_list_item_new_with_label( item );
296 }
297
298 gtk_signal_connect( GTK_OBJECT(list_item), "select",
299 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
300
301 if (GetWindowStyleFlag() & wxLB_MULTIPLE)
302 gtk_signal_connect( GTK_OBJECT(list_item), "deselect",
303 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
304
305 gtk_container_add( GTK_CONTAINER(m_list), list_item );
306
307 if (m_widgetStyle) ApplyWidgetStyle();
308
309 gtk_signal_connect( GTK_OBJECT(list_item),
310 "button_press_event",
311 (GtkSignalFunc)gtk_listbox_button_press_callback,
312 (gpointer) this );
313
314 if (m_hasCheckBoxes)
315 {
316 gtk_signal_connect( GTK_OBJECT(list_item),
317 "key_press_event",
318 (GtkSignalFunc)gtk_listbox_key_press_callback,
319 (gpointer)this );
320 }
321
322 gtk_widget_show( list_item );
323
324 ConnectWidget( list_item );
325
326#if wxUSE_DRAG_AND_DROP
327#ifndef NEW_GTK_DND_CODE
328 if (m_dropTarget) m_dropTarget->RegisterWidget( list_item );
329#endif
330#endif
331}
332
333void wxListBox::Append( const wxString &item )
334{
335 m_clientDataList.Append( (wxObject*) NULL );
336 m_clientObjectList.Append( (wxObject*) NULL );
337
338 AppendCommon( item );
339}
340
341void wxListBox::Append( const wxString &item, void *clientData )
342{
343 m_clientDataList.Append( (wxObject*) clientData );
344 m_clientObjectList.Append( (wxObject*) NULL );
345
346 AppendCommon( item );
347}
348
349void wxListBox::Append( const wxString &item, wxClientData *clientData )
350{
351 m_clientObjectList.Append( (wxObject*) clientData );
352 m_clientDataList.Append( (wxObject*) NULL );
353
354 AppendCommon( item );
355}
356
357void wxListBox::SetClientData( int n, void* clientData )
358{
359 wxCHECK_RET( m_widget != NULL, "invalid combobox" );
360
361 wxNode *node = m_clientDataList.Nth( n );
362 if (!node) return;
363
364 node->SetData( (wxObject*) clientData );
365}
366
367void* wxListBox::GetClientData( int n )
368{
369 wxCHECK_MSG( m_widget != NULL, NULL, "invalid combobox" );
370
371 wxNode *node = m_clientDataList.Nth( n );
372 if (!node) return NULL;
373
374 return node->Data();
375}
376
377void wxListBox::SetClientObject( int n, wxClientData* clientData )
378{
379 wxCHECK_RET( m_widget != NULL, "invalid combobox" );
380
381 wxNode *node = m_clientObjectList.Nth( n );
382 if (!node) return;
383
384 wxClientData *cd = (wxClientData*) node->Data();
385 if (cd) delete cd;
386
387 node->SetData( (wxObject*) clientData );
388}
389
390wxClientData* wxListBox::GetClientObject( int n )
391{
392 wxCHECK_MSG( m_widget != NULL, (wxClientData*)NULL, "invalid combobox" );
393
394 wxNode *node = m_clientObjectList.Nth( n );
395 if (!node) return (wxClientData*) NULL;
396
397 return (wxClientData*) node->Data();
398}
399
400void wxListBox::Clear()
401{
402 wxCHECK_RET( m_list != NULL, "invalid listbox" );
403
404 gtk_list_clear_items( m_list, 0, Number() );
405
406 wxNode *node = m_clientObjectList.First();
407 while (node)
408 {
409 wxClientData *cd = (wxClientData*)node->Data();
410 if (cd) delete cd;
411 node = node->Next();
412 }
413 m_clientObjectList.Clear();
414
415 m_clientDataList.Clear();
416}
417
418void wxListBox::Delete( int n )
419{
420 wxCHECK_RET( m_list != NULL, "invalid listbox" );
421
422 GList *child = g_list_nth( m_list->children, n );
423
424 wxCHECK_RET( child, "wrong listbox index" );
425
426 GList *list = g_list_append( (GList*) NULL, child->data );
427 gtk_list_remove_items( m_list, list );
428 g_list_free( list );
429
430 wxNode *node = m_clientObjectList.Nth( n );
431 if (node)
432 {
433 wxClientData *cd = (wxClientData*)node->Data();
434 if (cd) delete cd;
435 m_clientObjectList.DeleteNode( node );
436 }
437
438 node = m_clientDataList.Nth( n );
439 if (node)
440 {
441 m_clientDataList.DeleteNode( node );
442 }
443}
444
445void wxListBox::Deselect( int n )
446{
447 wxCHECK_RET( m_list != NULL, "invalid listbox" );
448
449 gtk_list_unselect_item( m_list, n );
450}
451
452int wxListBox::FindString( const wxString &item ) const
453{
454 wxCHECK_MSG( m_list != NULL, -1, "invalid listbox" );
455
456 GList *child = m_list->children;
457 int count = 0;
458 while (child)
459 {
460 GtkBin *bin = GTK_BIN( child->data );
461 GtkLabel *label = GTK_LABEL( bin->child );
462
463 wxString str = label->label;
464 if (m_hasCheckBoxes) str.Remove( 0, 4 );
465
466 if (str == item) return count;
467
468 count++;
469 child = child->next;
470 }
471
472 // it's not an error if the string is not found -> no wxCHECK
473
474 return -1;
475}
476
477int wxListBox::GetSelection() const
478{
479 wxCHECK_MSG( m_list != NULL, -1, "invalid listbox" );
480
481 GList *child = m_list->children;
482 int count = 0;
483 while (child)
484 {
485 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED) return count;
486 count++;
487 child = child->next;
488 }
489 return -1;
490}
491
492int wxListBox::GetSelections( wxArrayInt& aSelections ) const
493{
494 wxCHECK_MSG( m_list != NULL, -1, "invalid listbox" );
495
496 // get the number of selected items first
497 GList *child = m_list->children;
498 int count = 0;
499 for (child = m_list->children; child != NULL; child = child->next)
500 {
501 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED)
502 count++;
503 }
504
505 aSelections.Empty();
506
507 if (count > 0)
508 {
509 // now fill the list
510 aSelections.Alloc(count); // optimization attempt
511 int i = 0;
512 for (child = m_list->children; child != NULL; child = child->next, i++)
513 {
514 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED)
515 aSelections.Add(i);
516 }
517 }
518
519 return count;
520}
521
522wxString wxListBox::GetString( int n ) const
523{
524 wxCHECK_MSG( m_list != NULL, "", "invalid listbox" );
525
526 GList *child = g_list_nth( m_list->children, n );
527 if (child)
528 {
529 GtkBin *bin = GTK_BIN( child->data );
530 GtkLabel *label = GTK_LABEL( bin->child );
531
532 wxString str = label->label;
533 if (m_hasCheckBoxes) str.Remove( 0, 4 );
534
535 return str;
536 }
537 wxFAIL_MSG("wrong listbox index");
538 return "";
539}
540
541wxString wxListBox::GetStringSelection() const
542{
543 wxCHECK_MSG( m_list != NULL, "", "invalid listbox" );
544
545 GList *selection = m_list->selection;
546 if (selection)
547 {
548 GtkBin *bin = GTK_BIN( selection->data );
549 GtkLabel *label = GTK_LABEL( bin->child );
550
551 wxString str = label->label;
552 if (m_hasCheckBoxes) str.Remove( 0, 4 );
553
554 return str;
555 }
556
557 wxFAIL_MSG("no listbox selection available");
558 return "";
559}
560
561int wxListBox::Number()
562{
563 wxCHECK_MSG( m_list != NULL, -1, "invalid listbox" );
564
565 GList *child = m_list->children;
566 int count = 0;
567 while (child) { count++; child = child->next; }
568 return count;
569}
570
571bool wxListBox::Selected( int n )
572{
573 wxCHECK_MSG( m_list != NULL, FALSE, "invalid listbox" );
574
575 GList *target = g_list_nth( m_list->children, n );
576 if (target)
577 {
578 GList *child = m_list->selection;
579 while (child)
580 {
581 if (child->data == target->data) return TRUE;
582 child = child->next;
583 }
584 }
585 wxFAIL_MSG("wrong listbox index");
586 return FALSE;
587}
588
589void wxListBox::Set( int WXUNUSED(n), const wxString *WXUNUSED(choices) )
590{
591 wxFAIL_MSG("wxListBox::Set not implemented");
592}
593
594void wxListBox::SetFirstItem( int WXUNUSED(n) )
595{
596 wxFAIL_MSG("wxListBox::SetFirstItem not implemented");
597}
598
599void wxListBox::SetFirstItem( const wxString &WXUNUSED(item) )
600{
601 wxFAIL_MSG("wxListBox::SetFirstItem not implemented");
602}
603
604void wxListBox::SetSelection( int n, bool select )
605{
606 wxCHECK_RET( m_list != NULL, "invalid listbox" );
607
608 if (select)
609 gtk_list_select_item( m_list, n );
610 else
611 gtk_list_unselect_item( m_list, n );
612}
613
614void wxListBox::SetString( int n, const wxString &string )
615{
616 wxCHECK_RET( m_list != NULL, "invalid listbox" );
617
618 GList *child = g_list_nth( m_list->children, n );
619 if (child)
620 {
621 GtkBin *bin = GTK_BIN( child->data );
622 GtkLabel *label = GTK_LABEL( bin->child );
623
624 wxString str;
625 if (m_hasCheckBoxes) str += "[-] ";
626 str += string;
627
628 gtk_label_set( label, str );
629 }
630 else
631 {
632 wxFAIL_MSG("wrong listbox index");
633 }
634}
635
636void wxListBox::SetStringSelection( const wxString &string, bool select )
637{
638 wxCHECK_RET( m_list != NULL, "invalid listbox" );
639
640 SetSelection( FindString(string), select );
641}
642
643int wxListBox::GetIndex( GtkWidget *item ) const
644{
645 if (item)
646 {
647 GList *child = m_list->children;
648 int count = 0;
649 while (child)
650 {
651 if (GTK_WIDGET(child->data) == item) return count;
652 count++;
653 child = child->next;
654 }
655 }
656 return -1;
657}
658
659#if wxUSE_DRAG_AND_DROP
660void wxListBox::SetDropTarget( wxDropTarget *dropTarget )
661{
662 wxCHECK_RET( m_list != NULL, "invalid listbox" );
663
664#ifndef NEW_GTK_DND_CODE
665 if (m_dropTarget)
666 {
667 GList *child = m_list->children;
668 while (child)
669 {
670 m_dropTarget->UnregisterWidget( GTK_WIDGET( child->data ) );
671 child = child->next;
672 }
673 }
674#endif
675
676 wxWindow::SetDropTarget( dropTarget );
677
678#ifndef NEW_GTK_DND_CODE
679 if (m_dropTarget)
680 {
681 GList *child = m_list->children;
682 while (child)
683 {
684 m_dropTarget->RegisterWidget( GTK_WIDGET( child->data ) );
685 child = child->next;
686 }
687 }
688#endif
689}
690#endif
691
692GtkWidget *wxListBox::GetConnectWidget()
693{
694 return GTK_WIDGET(m_list);
695}
696
697bool wxListBox::IsOwnGtkWindow( GdkWindow *window )
698{
699 if (wxWindow::IsOwnGtkWindow( window )) return TRUE;
700
701 GList *child = m_list->children;
702 while (child)
703 {
704 GtkWidget *bin = GTK_WIDGET( child->data );
705 if (bin->window == window) return TRUE;
706 child = child->next;
707 }
708
709 return FALSE;
710}
711
712void wxListBox::ApplyWidgetStyle()
713{
714 SetWidgetStyle();
715
716 if (m_backgroundColour.Ok())
717 {
718 GdkWindow *window = GTK_WIDGET(m_list)->window;
719 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
720 gdk_window_set_background( window, m_backgroundColour.GetColor() );
721 gdk_window_clear( window );
722 }
723
724 GList *child = m_list->children;
725 while (child)
726 {
727 gtk_widget_set_style( GTK_WIDGET(child->data), m_widgetStyle );
728
729 GtkBin *bin = GTK_BIN( child->data );
730 GtkWidget *label = GTK_WIDGET( bin->child );
731 gtk_widget_set_style( label, m_widgetStyle );
732
733 child = child->next;
734 }
735}