]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/listbox.cpp
New wxDC hierarchy
[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/dynarray.h"
16 #include "wx/listbox.h"
17 #include "wx/utils.h"
18 #include <wx/intl.h>
19
20 //-------------------------------------------------------------------------
21 // conditional compilation
22 //-------------------------------------------------------------------------
23
24 #if (GTK_MINOR_VERSION == 1)
25 #if (GTK_MICRO_VERSION >= 5)
26 #define NEW_GTK_SCROLL_CODE
27 #endif
28 #endif
29
30 //-----------------------------------------------------------------------------
31 // data
32 //-----------------------------------------------------------------------------
33
34 extern bool g_blockEventsOnDrag;
35
36 //-----------------------------------------------------------------------------
37 // "select" and "deselect"
38 //-----------------------------------------------------------------------------
39
40 static void gtk_listitem_select_callback( GtkWidget *WXUNUSED(widget), wxListBox *listbox )
41 {
42 if (!listbox->HasVMT()) return;
43 if (g_blockEventsOnDrag) return;
44
45 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, listbox->GetId() );
46
47 wxArrayInt aSelections;
48 int count = listbox->GetSelections(aSelections);
49 if ( count > 0 )
50 {
51 event.m_commandInt = aSelections[0] ;
52 event.m_clientData = listbox->GetClientData( event.m_commandInt );
53 wxString str(listbox->GetString(event.m_commandInt));
54 if (str != "") event.m_commandString = copystring((char *)(const char *)str);
55 }
56 else
57 {
58 event.m_commandInt = -1 ;
59 event.m_commandString = copystring("") ;
60 }
61
62 event.SetEventObject( listbox );
63
64 listbox->GetEventHandler()->ProcessEvent( event );
65 if (event.m_commandString) delete[] event.m_commandString ;
66 }
67
68 //-----------------------------------------------------------------------------
69 // wxListBox
70 //-----------------------------------------------------------------------------
71
72 IMPLEMENT_DYNAMIC_CLASS(wxListBox,wxControl)
73
74 wxListBox::wxListBox()
75 {
76 m_list = (GtkList *) NULL;
77 }
78
79 bool wxListBox::Create( wxWindow *parent, wxWindowID id,
80 const wxPoint &pos, const wxSize &size,
81 int n, const wxString choices[],
82 long style, const wxValidator& validator, const wxString &name )
83 {
84 m_needParent = TRUE;
85
86 PreCreation( parent, id, pos, size, style, name );
87
88 SetValidator( validator );
89
90 m_widget = gtk_scrolled_window_new( (GtkAdjustment*) NULL, (GtkAdjustment*) NULL );
91 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(m_widget),
92 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
93
94 m_list = GTK_LIST( gtk_list_new() );
95
96 GtkSelectionMode mode = GTK_SELECTION_BROWSE;
97 if (style & wxLB_MULTIPLE)
98 mode = GTK_SELECTION_MULTIPLE;
99 else if (style & wxLB_EXTENDED)
100 mode = GTK_SELECTION_EXTENDED;
101
102 gtk_list_set_selection_mode( GTK_LIST(m_list), mode );
103
104 #ifdef NEW_GTK_SCROLL_CODE
105 gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(m_widget), GTK_WIDGET(m_list) );
106 #else
107 gtk_container_add( GTK_CONTAINER(m_widget), GTK_WIDGET(m_list) );
108 #endif
109
110 gtk_widget_show( GTK_WIDGET(m_list) );
111
112 wxSize newSize = size;
113 if (newSize.x == -1) newSize.x = 100;
114 if (newSize.y == -1) newSize.y = 110;
115 SetSize( newSize.x, newSize.y );
116
117 for (int i = 0; i < n; i++)
118 {
119 m_clientDataList.Append( (wxObject*) NULL );
120 m_clientObjectList.Append( (wxObject*) NULL );
121
122 GtkWidget *list_item;
123 list_item = gtk_list_item_new_with_label( choices[i] );
124
125 gtk_container_add( GTK_CONTAINER(m_list), list_item );
126
127 gtk_signal_connect( GTK_OBJECT(list_item), "select",
128 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
129
130 if (style & wxLB_MULTIPLE)
131 gtk_signal_connect( GTK_OBJECT(list_item), "deselect",
132 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
133
134 ConnectWidget( list_item );
135
136 gtk_widget_show( list_item );
137 }
138
139 m_parent->AddChild( this );
140
141 (m_parent->m_insertCallback)( m_parent, this );
142
143 PostCreation();
144
145 gtk_widget_realize( GTK_WIDGET(m_list) );
146
147 SetBackgroundColour( parent->GetBackgroundColour() );
148 SetForegroundColour( parent->GetForegroundColour() );
149
150 Show( TRUE );
151
152 return TRUE;
153 }
154
155 wxListBox::~wxListBox()
156 {
157 Clear();
158 }
159
160 void wxListBox::AppendCommon( const wxString &item )
161 {
162 wxCHECK_RET( m_list != NULL, "invalid listbox" );
163
164 GtkWidget *list_item = gtk_list_item_new_with_label( item );
165
166 gtk_signal_connect( GTK_OBJECT(list_item), "select",
167 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
168
169 if (GetWindowStyleFlag() & wxLB_MULTIPLE)
170 gtk_signal_connect( GTK_OBJECT(list_item), "deselect",
171 GTK_SIGNAL_FUNC(gtk_listitem_select_callback), (gpointer)this );
172
173 gtk_container_add( GTK_CONTAINER(m_list), list_item );
174
175 if (m_widgetStyle) ApplyWidgetStyle();
176
177 gtk_widget_show( list_item );
178
179 ConnectWidget( list_item );
180
181 #ifndef NEW_GTK_DND_CODE
182 if (m_dropTarget) m_dropTarget->RegisterWidget( list_item );
183 #endif
184 }
185
186 void wxListBox::Append( const wxString &item )
187 {
188 m_clientDataList.Append( (wxObject*) NULL );
189 m_clientObjectList.Append( (wxObject*) NULL );
190
191 AppendCommon( item );
192 }
193
194 void wxListBox::Append( const wxString &item, void *clientData )
195 {
196 m_clientDataList.Append( (wxObject*) clientData );
197 m_clientObjectList.Append( (wxObject*) NULL );
198
199 AppendCommon( item );
200 }
201
202 void wxListBox::Append( const wxString &item, wxClientData *clientData )
203 {
204 m_clientObjectList.Append( (wxObject*) clientData );
205 m_clientDataList.Append( (wxObject*) NULL );
206
207 AppendCommon( item );
208 }
209
210 void wxListBox::SetClientData( int n, void* clientData )
211 {
212 wxCHECK_RET( m_widget != NULL, "invalid combobox" );
213
214 wxNode *node = m_clientDataList.Nth( n );
215 if (!node) return;
216
217 node->SetData( (wxObject*) clientData );
218 }
219
220 void* wxListBox::GetClientData( int n )
221 {
222 wxCHECK_MSG( m_widget != NULL, NULL, "invalid combobox" );
223
224 wxNode *node = m_clientDataList.Nth( n );
225 if (!node) return NULL;
226
227 return node->Data();
228 }
229
230 void wxListBox::SetClientObject( int n, wxClientData* clientData )
231 {
232 wxCHECK_RET( m_widget != NULL, "invalid combobox" );
233
234 wxNode *node = m_clientObjectList.Nth( n );
235 if (!node) return;
236
237 wxClientData *cd = (wxClientData*) node->Data();
238 if (cd) delete cd;
239
240 node->SetData( (wxObject*) clientData );
241 }
242
243 wxClientData* wxListBox::GetClientObject( int n )
244 {
245 wxCHECK_MSG( m_widget != NULL, (wxClientData*)NULL, "invalid combobox" );
246
247 wxNode *node = m_clientObjectList.Nth( n );
248 if (!node) return (wxClientData*) NULL;
249
250 return (wxClientData*) node->Data();
251 }
252
253 void wxListBox::Clear()
254 {
255 wxCHECK_RET( m_list != NULL, "invalid listbox" );
256
257 gtk_list_clear_items( m_list, 0, Number() );
258
259 wxNode *node = m_clientObjectList.First();
260 while (node)
261 {
262 wxClientData *cd = (wxClientData*)node->Data();
263 if (cd) delete cd;
264 node = node->Next();
265 }
266 m_clientObjectList.Clear();
267
268 m_clientDataList.Clear();
269 }
270
271 void wxListBox::Delete( int n )
272 {
273 wxCHECK_RET( m_list != NULL, "invalid listbox" );
274
275 GList *child = g_list_nth( m_list->children, n );
276
277 if (!child)
278 {
279 wxFAIL_MSG("wrong listbox index");
280 return;
281 }
282
283 GList *list = g_list_append( NULL, child->data );
284 gtk_list_remove_items( m_list, list );
285 g_list_free( list );
286
287 wxNode *node = m_clientObjectList.Nth( n );
288 if (node)
289 {
290 wxClientData *cd = (wxClientData*)node->Data();
291 if (cd) delete cd;
292 m_clientObjectList.DeleteNode( node );
293 }
294
295 node = m_clientDataList.Nth( n );
296 if (node)
297 {
298 m_clientDataList.DeleteNode( node );
299 }
300 }
301
302 void wxListBox::Deselect( int n )
303 {
304 wxCHECK_RET( m_list != NULL, "invalid listbox" );
305
306 gtk_list_unselect_item( m_list, n );
307 }
308
309 int wxListBox::FindString( const wxString &item ) const
310 {
311 wxCHECK_MSG( m_list != NULL, -1, "invalid listbox" );
312
313 GList *child = m_list->children;
314 int count = 0;
315 while (child)
316 {
317 GtkBin *bin = GTK_BIN( child->data );
318 GtkLabel *label = GTK_LABEL( bin->child );
319 if (item == label->label) return count;
320 count++;
321 child = child->next;
322 }
323
324 // it's not an error if the string is not found -> no wxCHECK
325
326 return -1;
327 }
328
329 int wxListBox::GetSelection() const
330 {
331 wxCHECK_MSG( m_list != NULL, -1, "invalid listbox" );
332
333 GList *child = m_list->children;
334 int count = 0;
335 while (child)
336 {
337 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED) return count;
338 count++;
339 child = child->next;
340 }
341 return -1;
342 }
343
344 int wxListBox::GetSelections( wxArrayInt& aSelections ) const
345 {
346 wxCHECK_MSG( m_list != NULL, -1, "invalid listbox" );
347
348 // get the number of selected items first
349 GList *child = m_list->children;
350 int count = 0;
351 for (child = m_list->children; child != NULL; child = child->next)
352 {
353 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED)
354 count++;
355 }
356
357 aSelections.Empty();
358
359 if (count > 0)
360 {
361 // now fill the list
362 aSelections.Alloc(count); // optimization attempt
363 int i = 0;
364 for (child = m_list->children; child != NULL; child = child->next, i++)
365 {
366 if (GTK_WIDGET(child->data)->state == GTK_STATE_SELECTED)
367 aSelections.Add(i);
368 }
369 }
370
371 return count;
372 }
373
374 wxString wxListBox::GetString( int n ) const
375 {
376 wxCHECK_MSG( m_list != NULL, "", "invalid listbox" );
377
378 GList *child = g_list_nth( m_list->children, n );
379 if (child)
380 {
381 GtkBin *bin = GTK_BIN( child->data );
382 GtkLabel *label = GTK_LABEL( bin->child );
383 return label->label;
384 }
385 wxFAIL_MSG("wrong listbox index");
386 return "";
387 }
388
389 wxString wxListBox::GetStringSelection() const
390 {
391 wxCHECK_MSG( m_list != NULL, "", "invalid listbox" );
392
393 GList *selection = m_list->selection;
394 if (selection)
395 {
396 GtkBin *bin = GTK_BIN( selection->data );
397 wxString tmp = GTK_LABEL( bin->child )->label;
398 return tmp;
399 }
400 wxFAIL_MSG("no listbox selection available");
401 return "";
402 }
403
404 int wxListBox::Number()
405 {
406 wxCHECK_MSG( m_list != NULL, -1, "invalid listbox" );
407
408 GList *child = m_list->children;
409 int count = 0;
410 while (child) { count++; child = child->next; }
411 return count;
412 }
413
414 bool wxListBox::Selected( int n )
415 {
416 wxCHECK_MSG( m_list != NULL, FALSE, "invalid listbox" );
417
418 GList *target = g_list_nth( m_list->children, n );
419 if (target)
420 {
421 GList *child = m_list->selection;
422 while (child)
423 {
424 if (child->data == target->data) return TRUE;
425 child = child->next;
426 }
427 }
428 wxFAIL_MSG("wrong listbox index");
429 return FALSE;
430 }
431
432 void wxListBox::Set( int WXUNUSED(n), const wxString *WXUNUSED(choices) )
433 {
434 wxFAIL_MSG("wxListBox::Set not implemented");
435 }
436
437 void wxListBox::SetFirstItem( int WXUNUSED(n) )
438 {
439 wxFAIL_MSG("wxListBox::SetFirstItem not implemented");
440 }
441
442 void wxListBox::SetFirstItem( const wxString &WXUNUSED(item) )
443 {
444 wxFAIL_MSG("wxListBox::SetFirstItem not implemented");
445 }
446
447 void wxListBox::SetSelection( int n, bool select )
448 {
449 wxCHECK_RET( m_list != NULL, "invalid listbox" );
450
451 if (select)
452 gtk_list_select_item( m_list, n );
453 else
454 gtk_list_unselect_item( m_list, n );
455 }
456
457 void wxListBox::SetString( int n, const wxString &string )
458 {
459 wxCHECK_RET( m_list != NULL, "invalid listbox" );
460
461 GList *child = g_list_nth( m_list->children, n );
462 if (child)
463 {
464 GtkBin *bin = GTK_BIN( child->data );
465 GtkLabel *label = GTK_LABEL( bin->child );
466 gtk_label_set( label, string );
467 }
468 else
469 {
470 wxFAIL_MSG("wrong listbox index");
471 }
472 }
473
474 void wxListBox::SetStringSelection( const wxString &string, bool select )
475 {
476 wxCHECK_RET( m_list != NULL, "invalid listbox" );
477
478 SetSelection( FindString(string), select );
479 }
480
481 int wxListBox::GetIndex( GtkWidget *item ) const
482 {
483 if (item)
484 {
485 GList *child = m_list->children;
486 int count = 0;
487 while (child)
488 {
489 if (GTK_WIDGET(child->data) == item) return count;
490 count++;
491 child = child->next;
492 }
493 }
494 return -1;
495 }
496
497 void wxListBox::SetDropTarget( wxDropTarget *dropTarget )
498 {
499 wxCHECK_RET( m_list != NULL, "invalid listbox" );
500
501 #ifndef NEW_GTK_DND_CODE
502 if (m_dropTarget)
503 {
504 GList *child = m_list->children;
505 while (child)
506 {
507 m_dropTarget->UnregisterWidget( GTK_WIDGET( child->data ) );
508 child = child->next;
509 }
510 }
511 #endif
512
513 wxWindow::SetDropTarget( dropTarget );
514
515 #ifndef NEW_GTK_DND_CODE
516 if (m_dropTarget)
517 {
518 GList *child = m_list->children;
519 while (child)
520 {
521 m_dropTarget->RegisterWidget( GTK_WIDGET( child->data ) );
522 child = child->next;
523 }
524 }
525 #endif
526 }
527
528 GtkWidget *wxListBox::GetConnectWidget()
529 {
530 return GTK_WIDGET(m_list);
531 }
532
533 bool wxListBox::IsOwnGtkWindow( GdkWindow *window )
534 {
535 if (wxWindow::IsOwnGtkWindow( window )) return TRUE;
536
537 GList *child = m_list->children;
538 while (child)
539 {
540 GtkWidget *bin = GTK_WIDGET( child->data );
541 if (bin->window == window) return TRUE;
542 child = child->next;
543 }
544
545 return FALSE;
546 }
547
548 void wxListBox::ApplyWidgetStyle()
549 {
550 SetWidgetStyle();
551
552 if (m_backgroundColour.Ok())
553 {
554 GdkWindow *window = GTK_WIDGET(m_list)->window;
555 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
556 gdk_window_set_background( window, m_backgroundColour.GetColor() );
557 gdk_window_clear( window );
558 }
559
560 GList *child = m_list->children;
561 while (child)
562 {
563 gtk_widget_set_style( GTK_BIN(child->data)->child, m_widgetStyle );
564 gtk_widget_set_style( GTK_WIDGET(child->data), m_widgetStyle );
565 child = child->next;
566 }
567 }