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