]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/motif/listbox.cpp
try to create smaller executables
[wxWidgets.git] / src / motif / listbox.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: listbox.cpp
3// Purpose: wxListBox
4// Author: Julian Smart
5// Modified by:
6// Created: 17/09/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
9// Licence: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13 #pragma implementation "listbox.h"
14#endif
15
16#ifdef __VMS
17#define XtParent XTPARENT
18#define XtDisplay XTDISPLAY
19#endif
20
21# include "wx/listbox.h"
22#include "wx/settings.h"
23#include "wx/dynarray.h"
24#include "wx/log.h"
25#include "wx/utils.h"
26
27#ifdef __VMS__
28#pragma message disable nosimpint
29#endif
30#include <Xm/List.h>
31#ifdef __VMS__
32#pragma message enable nosimpint
33#endif
34#include "wx/motif/private.h"
35
36 IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
37
38static void wxListBoxCallback(Widget w,
39 XtPointer clientData,
40 XmListCallbackStruct * cbs);
41
42// ----------------------------------------------------------------------------
43// wxSizeKeeper
44// ----------------------------------------------------------------------------
45
46// helper class to reduce code duplication
47class wxSizeKeeper
48{
49 int m_x, m_y;
50 wxWindow* m_w;
51public:
52 wxSizeKeeper( wxWindow* w )
53 : m_w( w )
54 {
55 m_w->GetSize( &m_x, &m_y );
56 }
57
58 void Restore()
59 {
60 int x, y;
61
62 m_w->GetSize( &x, &y );
63 if( x != m_x || y != m_y )
64 m_w->SetSize( -1, -1, m_x, m_y );
65 }
66};
67
68// ============================================================================
69// list box control implementation
70// ============================================================================
71
72// Listbox item
73wxListBox::wxListBox()
74{
75 m_noItems = 0;
76}
77
78bool wxListBox::Create(wxWindow *parent, wxWindowID id,
79 const wxPoint& pos,
80 const wxSize& size,
81 int n, const wxString choices[],
82 long style,
83 const wxValidator& validator,
84 const wxString& name)
85{
86 if( !wxControl::CreateControl( parent, id, pos, size, style,
87 validator, name ) )
88 return FALSE;
89
90 m_noItems = n;
91 m_backgroundColour = * wxWHITE;
92
93 Widget parentWidget = (Widget) parent->GetClientWidget();
94
95 Arg args[3];
96 int count = 0;
97 XtSetArg( args[0], XmNlistSizePolicy, XmCONSTANT ); ++count;
98 XtSetArg( args[1], XmNselectionPolicy,
99 ( m_windowStyle & wxLB_MULTIPLE ) ? XmMULTIPLE_SELECT :
100 ( m_windowStyle & wxLB_EXTENDED ) ? XmEXTENDED_SELECT :
101 XmBROWSE_SELECT );
102 ++count;
103 if( m_windowStyle & wxLB_ALWAYS_SB )
104 {
105 XtSetArg( args[2], XmNscrollBarDisplayPolicy, XmSTATIC );
106 ++count;
107 }
108
109 Widget listWidget = XmCreateScrolledList(parentWidget,
110 (char*)name.c_str(), args, count);
111
112 m_mainWidget = (WXWidget) listWidget;
113
114 Set(n, choices);
115
116 XtManageChild (listWidget);
117
118 long width = size.x;
119 long height = size.y;
120 if (width == -1)
121 width = 150;
122 if (height == -1)
123 height = 80;
124
125 XtAddCallback (listWidget,
126 XmNbrowseSelectionCallback,
127 (XtCallbackProc) wxListBoxCallback,
128 (XtPointer) this);
129 XtAddCallback (listWidget,
130 XmNextendedSelectionCallback,
131 (XtCallbackProc) wxListBoxCallback,
132 (XtPointer) this);
133 XtAddCallback (listWidget,
134 XmNmultipleSelectionCallback,
135 (XtCallbackProc) wxListBoxCallback,
136 (XtPointer) this);
137 XtAddCallback (listWidget,
138 XmNdefaultActionCallback,
139 (XtCallbackProc) wxListBoxCallback,
140 (XtPointer) this);
141
142 ChangeFont(FALSE);
143
144 SetCanAddEventHandler(TRUE);
145 AttachWidget (parent, m_mainWidget, (WXWidget) NULL,
146 pos.x, pos.y, width, height);
147
148 ChangeBackgroundColour();
149
150 return TRUE;
151}
152
153wxListBox::~wxListBox()
154{
155 if( HasClientObjectData() )
156 m_clientDataDict.DestroyData();
157}
158
159void wxListBox::SetSelectionPolicy()
160{
161 Widget listBox = (Widget)m_mainWidget;
162 Arg args[3];
163
164 XtSetArg( args[0], XmNlistSizePolicy, XmCONSTANT );
165
166 XtSetArg( args[1], XmNselectionPolicy,
167 ( m_windowStyle & wxLB_MULTIPLE ) ? XmMULTIPLE_SELECT :
168 ( m_windowStyle & wxLB_EXTENDED ) ? XmEXTENDED_SELECT :
169 XmBROWSE_SELECT );
170
171 XtSetValues( listBox, args, 2 );
172}
173
174void wxListBox::DoSetFirstItem( int N )
175{
176 int count, length;
177
178 if (N < 0)
179 return;
180 XtVaGetValues ((Widget) m_mainWidget,
181 XmNvisibleItemCount, &count,
182 XmNitemCount, &length,
183 NULL);
184 if ((N + count) >= length)
185 N = length - count;
186 XmListSetPos ((Widget) m_mainWidget, N + 1);
187}
188
189void wxListBox::Delete(int N)
190{
191 wxSizeKeeper sk( this );
192 Widget listBox = (Widget) m_mainWidget;
193
194 bool managed = XtIsManaged(listBox);
195
196 if (managed)
197 XtUnmanageChild (listBox);
198
199 XmListDeletePos (listBox, N + 1);
200
201 if (managed)
202 XtManageChild (listBox);
203
204 sk.Restore();
205 m_clientDataDict.Delete(N, HasClientObjectData());
206 m_noItems --;
207}
208
209int wxListBox::DoAppend(const wxString& item)
210{
211 wxSizeKeeper sk( this );
212 Widget listBox = (Widget) m_mainWidget;
213
214 bool managed = XtIsManaged(listBox);
215
216 if (managed)
217 XtUnmanageChild (listBox);
218 int n;
219 XtVaGetValues (listBox, XmNitemCount, &n, NULL);
220 wxXmString text( item );
221 // XmListAddItem(listBox, text, n + 1);
222 XmListAddItemUnselected (listBox, text(), 0);
223
224 // It seems that if the list is cleared, we must re-ask for
225 // selection policy!!
226 SetSelectionPolicy();
227
228 if (managed)
229 XtManageChild (listBox);
230
231 sk.Restore();
232 m_noItems ++;
233
234 return GetCount() - 1;
235}
236
237void wxListBox::DoSetItems(const wxArrayString& items, void** clientData)
238{
239 wxSizeKeeper sk( this );
240 Widget listBox = (Widget) m_mainWidget;
241
242 if( HasClientObjectData() )
243 m_clientDataDict.DestroyData();
244
245 bool managed = XtIsManaged(listBox);
246
247 if (managed)
248 XtUnmanageChild (listBox);
249 XmString *text = new XmString[items.GetCount()];
250 size_t i;
251 for (i = 0; i < items.GetCount(); ++i)
252 text[i] = XmStringCreateSimple ((char*)items[i].c_str());
253
254 if ( clientData )
255 for (i = 0; i < items.GetCount(); ++i)
256 m_clientDataDict.Set(i, (wxClientData*)clientData[i], FALSE);
257
258 XmListAddItems (listBox, text, items.GetCount(), 0);
259 for (i = 0; i < items.GetCount(); i++)
260 XmStringFree (text[i]);
261 delete[] text;
262
263 // It seems that if the list is cleared, we must re-ask for
264 // selection policy!!
265 SetSelectionPolicy();
266
267 if (managed)
268 XtManageChild (listBox);
269
270 sk.Restore();
271
272 m_noItems = items.GetCount();
273}
274
275int wxListBox::FindString(const wxString& s) const
276{
277 wxXmString str( s );
278 int *positions = NULL;
279 int no_positions = 0;
280 bool success = XmListGetMatchPos ((Widget) m_mainWidget, str(),
281 &positions, &no_positions);
282
283 if (success)
284 {
285 int pos = positions[0];
286 if (positions)
287 XtFree ((char *) positions);
288 return pos - 1;
289 }
290 else
291 return -1;
292}
293
294void wxListBox::Clear()
295{
296 if (m_noItems <= 0)
297 return;
298
299 wxSizeKeeper sk( this );
300 Widget listBox = (Widget) m_mainWidget;
301
302 XmListDeleteAllItems (listBox);
303 if( HasClientObjectData() )
304 m_clientDataDict.DestroyData();
305
306 sk.Restore();
307
308 m_noItems = 0;
309}
310
311void wxListBox::SetSelection(int N, bool select)
312{
313 m_inSetValue = TRUE;
314 if (select)
315 {
316#if 0
317 if (m_windowStyle & wxLB_MULTIPLE)
318 {
319 int *selections = NULL;
320 int n = GetSelections (&selections);
321
322 // This hack is supposed to work, to make it possible
323 // to select more than one item, but it DOESN'T under Motif 1.1.
324
325 XtVaSetValues ((Widget) m_mainWidget,
326 XmNselectionPolicy, XmMULTIPLE_SELECT,
327 NULL);
328
329 int i;
330 for (i = 0; i < n; i++)
331 XmListSelectPos ((Widget) m_mainWidget,
332 selections[i] + 1, FALSE);
333
334 XmListSelectPos ((Widget) m_mainWidget, N + 1, FALSE);
335
336 XtVaSetValues ((Widget) m_mainWidget,
337 XmNselectionPolicy, XmEXTENDED_SELECT,
338 NULL);
339 }
340 else
341#endif // 0
342 XmListSelectPos ((Widget) m_mainWidget, N + 1, FALSE);
343
344 }
345 else
346 XmListDeselectPos ((Widget) m_mainWidget, N + 1);
347
348 m_inSetValue = FALSE;
349}
350
351bool wxListBox::IsSelected(int N) const
352{
353 // In Motif, no simple way to determine if the item is selected.
354 wxArrayInt theSelections;
355 int count = GetSelections (theSelections);
356 if (count == 0)
357 return FALSE;
358 else
359 {
360 int j;
361 for (j = 0; j < count; j++)
362 if (theSelections[j] == N)
363 return TRUE;
364 }
365 return FALSE;
366}
367
368void wxListBox::DoSetItemClientObject(int n, wxClientData* clientData)
369{
370 m_clientDataDict.Set(n, clientData, FALSE);
371}
372
373wxClientData* wxListBox::DoGetItemClientObject(int n) const
374{
375 return m_clientDataDict.Get(n);
376}
377
378void *wxListBox::DoGetItemClientData(int N) const
379{
380 return (void*)m_clientDataDict.Get(N);
381}
382
383void wxListBox::DoSetItemClientData(int N, void *Client_data)
384{
385 m_clientDataDict.Set(N, (wxClientData*)Client_data, FALSE);
386}
387
388// Return number of selections and an array of selected integers
389int wxListBox::GetSelections(wxArrayInt& aSelections) const
390{
391 aSelections.Empty();
392
393 Widget listBox = (Widget) m_mainWidget;
394 int *posList = NULL;
395 int posCnt = 0;
396 bool flag = XmListGetSelectedPos (listBox, &posList, &posCnt);
397 if (flag)
398 {
399 if (posCnt > 0)
400 {
401 aSelections.Alloc(posCnt);
402
403 int i;
404 for (i = 0; i < posCnt; i++)
405 aSelections.Add(posList[i] - 1);
406
407 XtFree ((char *) posList);
408 return posCnt;
409 }
410 else
411 return 0;
412 }
413 else
414 return 0;
415}
416
417// Get single selection, for single choice list items
418int wxListBox::GetSelection() const
419{
420 Widget listBox = (Widget) m_mainWidget;
421 int *posList = NULL;
422 int posCnt = 0;
423 bool flag = XmListGetSelectedPos (listBox, &posList, &posCnt);
424 if (flag)
425 {
426 int id = -1;
427 if (posCnt > 0)
428 id = posList[0] - 1;
429 XtFree ((char *) posList);
430 return id;
431 }
432 else
433 return -1;
434}
435
436// Find string for position
437wxString wxListBox::GetString(int N) const
438{
439 Widget listBox = (Widget) m_mainWidget;
440 XmString *strlist;
441 int n;
442 XtVaGetValues (listBox, XmNitemCount, &n, XmNitems, &strlist, NULL);
443 if (N <= n && N >= 0)
444 {
445 char *txt;
446 if (XmStringGetLtoR (strlist[N], XmSTRING_DEFAULT_CHARSET, &txt))
447 {
448 wxString str(txt);
449 XtFree (txt);
450 return str;
451 }
452 else
453 return wxEmptyString;
454 }
455 else
456 return wxEmptyString;
457}
458
459void wxListBox::DoInsertItems(const wxArrayString& items, int pos)
460{
461 wxSizeKeeper sk( this );
462 Widget listBox = (Widget) m_mainWidget;
463
464 bool managed = XtIsManaged(listBox);
465
466 if (managed)
467 XtUnmanageChild(listBox);
468
469 XmString *text = new XmString[items.GetCount()];
470 size_t i;
471 // Steve Hammes: Motif 1.1 compatibility
472 // #if XmVersion > 1100
473 // Corrected by Sergey Krasnov from Steve Hammes' code
474#if XmVersion > 1001
475 for (i = 0; i < items.GetCount(); i++)
476 text[i] = XmStringCreateSimple((char*)items[i].c_str());
477 XmListAddItemsUnselected(listBox, text, items.GetCount(), pos+1);
478#else
479 for (i = 0; i < items.GetCount(); i++)
480 {
481 text[i] = XmStringCreateSimple((char*)items[i].c_str());
482 // Another Sergey correction
483 XmListAddItemUnselected(listBox, text[i], pos+i+1);
484 }
485#endif
486 for (i = 0; i < items.GetCount(); i++)
487 XmStringFree(text[i]);
488 delete[] text;
489
490 // It seems that if the list is cleared, we must re-ask for
491 // selection policy!!
492 SetSelectionPolicy();
493
494 if (managed)
495 XtManageChild(listBox);
496
497 sk.Restore();
498
499 m_noItems += items.GetCount();
500}
501
502void wxListBox::SetString(int N, const wxString& s)
503{
504 wxSizeKeeper sk( this );
505 Widget listBox = (Widget) m_mainWidget;
506
507 wxXmString text( s );
508
509 // delete the item and add it again.
510 // FIXME isn't there a way to change it in place?
511 XmListDeletePos (listBox, N+1);
512 XmListAddItem (listBox, text(), N+1);
513
514 sk.Restore();
515}
516
517void wxListBox::Command (wxCommandEvent & event)
518{
519 if (event.m_extraLong)
520 SetSelection (event.m_commandInt);
521 else
522 {
523 Deselect (event.m_commandInt);
524 return;
525 }
526 ProcessCommand (event);
527}
528
529void wxListBoxCallback (Widget WXUNUSED(w), XtPointer clientData,
530 XmListCallbackStruct * cbs)
531{
532 wxListBox *item = (wxListBox *) clientData;
533
534 if (item->InSetValue())
535 return;
536
537 wxEventType evtType;
538
539 if( cbs->reason == XmCR_DEFAULT_ACTION )
540 evtType = wxEVT_COMMAND_LISTBOX_DOUBLECLICKED;
541 else
542 evtType = wxEVT_COMMAND_LISTBOX_SELECTED;
543
544 int n = cbs->item_position - 1;
545 wxCommandEvent event (evtType, item->GetId());
546 if ( item->HasClientObjectData() )
547 event.SetClientObject( item->GetClientObject(n) );
548 else if ( item->HasClientUntypedData() )
549 event.SetClientData( item->GetClientData(n) );
550 event.m_commandInt = n;
551 event.m_extraLong = TRUE;
552 event.SetEventObject(item);
553 event.SetString( item->GetString( n ) );
554
555 int x = -1;
556 if( NULL != cbs->event && cbs->event->type == ButtonRelease )
557 {
558 XButtonEvent* evt = (XButtonEvent*)cbs->event;
559
560 x = evt->x;
561 }
562
563 switch (cbs->reason)
564 {
565 case XmCR_MULTIPLE_SELECT:
566 case XmCR_BROWSE_SELECT:
567#if wxUSE_CHECKLISTBOX
568 item->DoToggleItem( n, x );
569#endif
570 case XmCR_DEFAULT_ACTION:
571 item->GetEventHandler()->ProcessEvent(event);
572 break;
573 case XmCR_EXTENDED_SELECT:
574 switch (cbs->selection_type)
575 {
576 case XmINITIAL:
577 case XmADDITION:
578 case XmMODIFICATION:
579 item->DoToggleItem( n, x );
580 item->GetEventHandler()->ProcessEvent(event);
581 break;
582 }
583 break;
584 }
585}
586
587WXWidget wxListBox::GetTopWidget() const
588{
589 return (WXWidget) XtParent( (Widget) m_mainWidget );
590}
591
592void wxListBox::ChangeBackgroundColour()
593{
594 wxWindow::ChangeBackgroundColour();
595
596 Widget parent = XtParent ((Widget) m_mainWidget);
597 Widget hsb, vsb;
598
599 XtVaGetValues (parent,
600 XmNhorizontalScrollBar, &hsb,
601 XmNverticalScrollBar, &vsb,
602 NULL);
603
604 /* TODO: should scrollbars be affected? Should probably have separate
605 * function to change them (by default, taken from wxSystemSettings)
606 */
607 wxColour backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
608 DoChangeBackgroundColour((WXWidget) hsb, backgroundColour, TRUE);
609 DoChangeBackgroundColour((WXWidget) vsb, backgroundColour, TRUE);
610
611 XtVaSetValues (hsb,
612 XmNtroughColor, backgroundColour.AllocColour(XtDisplay(hsb)),
613 NULL);
614 XtVaSetValues (vsb,
615 XmNtroughColor, backgroundColour.AllocColour(XtDisplay(vsb)),
616 NULL);
617
618 DoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, TRUE);
619}
620
621void wxListBox::ChangeForegroundColour()
622{
623 wxWindow::ChangeForegroundColour();
624
625 Widget parent = XtParent ((Widget) m_mainWidget);
626 Widget hsb, vsb;
627
628 XtVaGetValues(parent,
629 XmNhorizontalScrollBar, &hsb,
630 XmNverticalScrollBar, &vsb,
631 NULL);
632
633 /* TODO: should scrollbars be affected? Should probably have separate
634 function to change them (by default, taken from wxSystemSettings)
635
636 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
637 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
638 DoChangeForegroundColour((WXWidget) parent, m_foregroundColour);
639 */
640}
641
642int wxListBox::GetCount() const
643{
644 return m_noItems;
645}