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