1 ///////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "listbox.h"
17 #define XtParent XTPARENT
18 #define XtDisplay XTDISPLAY
21 # include "wx/listbox.h"
22 #include "wx/settings.h"
23 #include "wx/dynarray.h"
28 #pragma message disable nosimpint
32 #pragma message enable nosimpint
34 #include "wx/motif/private.h"
36 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControl
)
38 static void wxListBoxCallback(Widget w
,
40 XmListCallbackStruct
* cbs
);
42 // ----------------------------------------------------------------------------
44 // ----------------------------------------------------------------------------
46 // helper class to reduce code duplication
52 wxSizeKeeper( wxWindow
* w
)
55 m_w
->GetSize( &m_x
, &m_y
);
62 m_w
->GetSize( &x
, &y
);
63 if( x
!= m_x
|| y
!= m_y
)
64 m_w
->SetSize( -1, -1, m_x
, m_y
);
68 // ============================================================================
69 // list box control implementation
70 // ============================================================================
73 wxListBox::wxListBox()
78 bool wxListBox::Create(wxWindow
*parent
, wxWindowID id
,
81 int n
, const wxString choices
[],
83 const wxValidator
& validator
,
86 if( !wxControl::CreateControl( parent
, id
, pos
, size
, style
,
91 m_backgroundColour
= * wxWHITE
;
93 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
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
:
103 if( m_windowStyle
& wxLB_ALWAYS_SB
)
105 XtSetArg( args
[2], XmNscrollBarDisplayPolicy
, XmSTATIC
);
109 Widget listWidget
= XmCreateScrolledList(parentWidget
,
110 (char*)name
.c_str(), args
, count
);
112 m_mainWidget
= (WXWidget
) listWidget
;
116 XtManageChild (listWidget
);
119 long height
= size
.y
;
125 XtAddCallback (listWidget
,
126 XmNbrowseSelectionCallback
,
127 (XtCallbackProc
) wxListBoxCallback
,
129 XtAddCallback (listWidget
,
130 XmNextendedSelectionCallback
,
131 (XtCallbackProc
) wxListBoxCallback
,
133 XtAddCallback (listWidget
,
134 XmNmultipleSelectionCallback
,
135 (XtCallbackProc
) wxListBoxCallback
,
137 XtAddCallback (listWidget
,
138 XmNdefaultActionCallback
,
139 (XtCallbackProc
) wxListBoxCallback
,
144 SetCanAddEventHandler(TRUE
);
145 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
,
146 pos
.x
, pos
.y
, width
, height
);
148 ChangeBackgroundColour();
153 wxListBox::~wxListBox()
155 if( HasClientObjectData() )
156 m_clientDataDict
.DestroyData();
159 void wxListBox::SetSelectionPolicy()
161 Widget listBox
= (Widget
)m_mainWidget
;
164 XtSetArg( args
[0], XmNlistSizePolicy
, XmCONSTANT
);
166 XtSetArg( args
[1], XmNselectionPolicy
,
167 ( m_windowStyle
& wxLB_MULTIPLE
) ? XmMULTIPLE_SELECT
:
168 ( m_windowStyle
& wxLB_EXTENDED
) ? XmEXTENDED_SELECT
:
171 XtSetValues( listBox
, args
, 2 );
174 void wxListBox::DoSetFirstItem( int N
)
180 XtVaGetValues ((Widget
) m_mainWidget
,
181 XmNvisibleItemCount
, &count
,
182 XmNitemCount
, &length
,
184 if ((N
+ count
) >= length
)
186 XmListSetPos ((Widget
) m_mainWidget
, N
+ 1);
189 void wxListBox::Delete(int N
)
191 wxSizeKeeper
sk( this );
192 Widget listBox
= (Widget
) m_mainWidget
;
194 bool managed
= XtIsManaged(listBox
);
197 XtUnmanageChild (listBox
);
199 XmListDeletePos (listBox
, N
+ 1);
202 XtManageChild (listBox
);
205 m_clientDataDict
.Delete(N
, HasClientObjectData());
209 int wxListBox::DoAppend(const wxString
& item
)
211 wxSizeKeeper
sk( this );
212 Widget listBox
= (Widget
) m_mainWidget
;
214 bool managed
= XtIsManaged(listBox
);
217 XtUnmanageChild (listBox
);
219 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
220 wxXmString
text( item
);
221 // XmListAddItem(listBox, text, n + 1);
222 XmListAddItemUnselected (listBox
, text(), 0);
224 // It seems that if the list is cleared, we must re-ask for
225 // selection policy!!
226 SetSelectionPolicy();
229 XtManageChild (listBox
);
234 return GetCount() - 1;
237 void wxListBox::DoSetItems(const wxArrayString
& items
, void** clientData
)
239 wxSizeKeeper
sk( this );
240 Widget listBox
= (Widget
) m_mainWidget
;
242 if( HasClientObjectData() )
243 m_clientDataDict
.DestroyData();
245 bool managed
= XtIsManaged(listBox
);
248 XtUnmanageChild (listBox
);
249 XmString
*text
= new XmString
[items
.GetCount()];
251 for (i
= 0; i
< items
.GetCount(); ++i
)
252 text
[i
] = XmStringCreateSimple ((char*)items
[i
].c_str());
255 for (i
= 0; i
< items
.GetCount(); ++i
)
256 m_clientDataDict
.Set(i
, (wxClientData
*)clientData
[i
], FALSE
);
258 XmListAddItems (listBox
, text
, items
.GetCount(), 0);
259 for (i
= 0; i
< items
.GetCount(); i
++)
260 XmStringFree (text
[i
]);
263 // It seems that if the list is cleared, we must re-ask for
264 // selection policy!!
265 SetSelectionPolicy();
268 XtManageChild (listBox
);
272 m_noItems
= items
.GetCount();
275 int wxDoFindStringInList(Widget w
, const wxString
& s
)
278 int *positions
= NULL
;
279 int no_positions
= 0;
280 bool success
= XmListGetMatchPos (w
, str(),
281 &positions
, &no_positions
);
285 int pos
= positions
[0];
287 XtFree ((char *) positions
);
294 int wxListBox::FindString(const wxString
& s
) const
296 return wxDoFindStringInList( (Widget
)m_mainWidget
, s
);
299 void wxListBox::Clear()
304 wxSizeKeeper
sk( this );
305 Widget listBox
= (Widget
) m_mainWidget
;
307 XmListDeleteAllItems (listBox
);
308 if( HasClientObjectData() )
309 m_clientDataDict
.DestroyData();
316 void wxListBox::SetSelection(int N
, bool select
)
322 if (m_windowStyle
& wxLB_MULTIPLE
)
324 int *selections
= NULL
;
325 int n
= GetSelections (&selections
);
327 // This hack is supposed to work, to make it possible
328 // to select more than one item, but it DOESN'T under Motif 1.1.
330 XtVaSetValues ((Widget
) m_mainWidget
,
331 XmNselectionPolicy
, XmMULTIPLE_SELECT
,
335 for (i
= 0; i
< n
; i
++)
336 XmListSelectPos ((Widget
) m_mainWidget
,
337 selections
[i
] + 1, FALSE
);
339 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
341 XtVaSetValues ((Widget
) m_mainWidget
,
342 XmNselectionPolicy
, XmEXTENDED_SELECT
,
347 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
351 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
353 m_inSetValue
= FALSE
;
356 bool wxListBox::IsSelected(int N
) const
358 // In Motif, no simple way to determine if the item is selected.
359 wxArrayInt theSelections
;
360 int count
= GetSelections (theSelections
);
366 for (j
= 0; j
< count
; j
++)
367 if (theSelections
[j
] == N
)
373 void wxListBox::DoSetItemClientObject(int n
, wxClientData
* clientData
)
375 m_clientDataDict
.Set(n
, clientData
, FALSE
);
378 wxClientData
* wxListBox::DoGetItemClientObject(int n
) const
380 return m_clientDataDict
.Get(n
);
383 void *wxListBox::DoGetItemClientData(int N
) const
385 return (void*)m_clientDataDict
.Get(N
);
388 void wxListBox::DoSetItemClientData(int N
, void *Client_data
)
390 m_clientDataDict
.Set(N
, (wxClientData
*)Client_data
, FALSE
);
393 // Return number of selections and an array of selected integers
394 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const
398 Widget listBox
= (Widget
) m_mainWidget
;
401 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
406 aSelections
.Alloc(posCnt
);
409 for (i
= 0; i
< posCnt
; i
++)
410 aSelections
.Add(posList
[i
] - 1);
412 XtFree ((char *) posList
);
422 // Get single selection, for single choice list items
423 int wxDoGetSelectionInList(Widget listBox
)
427 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
433 XtFree ((char *) posList
);
440 int wxListBox::GetSelection() const
442 return wxDoGetSelectionInList((Widget
) m_mainWidget
);
445 // Find string for position
446 wxString
wxListBox::GetString(int N
) const
448 Widget listBox
= (Widget
) m_mainWidget
;
451 XtVaGetValues (listBox
, XmNitemCount
, &n
, XmNitems
, &strlist
, NULL
);
452 if (N
<= n
&& N
>= 0)
455 if (XmStringGetLtoR (strlist
[N
], XmSTRING_DEFAULT_CHARSET
, &txt
))
462 return wxEmptyString
;
465 return wxEmptyString
;
468 void wxListBox::DoInsertItems(const wxArrayString
& items
, int pos
)
470 wxSizeKeeper
sk( this );
471 Widget listBox
= (Widget
) m_mainWidget
;
473 bool managed
= XtIsManaged(listBox
);
476 XtUnmanageChild(listBox
);
478 XmString
*text
= new XmString
[items
.GetCount()];
480 // Steve Hammes: Motif 1.1 compatibility
481 // #if XmVersion > 1100
482 // Corrected by Sergey Krasnov from Steve Hammes' code
484 for (i
= 0; i
< items
.GetCount(); i
++)
485 text
[i
] = XmStringCreateSimple((char*)items
[i
].c_str());
486 XmListAddItemsUnselected(listBox
, text
, items
.GetCount(), pos
+1);
488 for (i
= 0; i
< items
.GetCount(); i
++)
490 text
[i
] = XmStringCreateSimple((char*)items
[i
].c_str());
491 // Another Sergey correction
492 XmListAddItemUnselected(listBox
, text
[i
], pos
+i
+1);
495 for (i
= 0; i
< items
.GetCount(); i
++)
496 XmStringFree(text
[i
]);
499 // It seems that if the list is cleared, we must re-ask for
500 // selection policy!!
501 SetSelectionPolicy();
504 XtManageChild(listBox
);
508 m_noItems
+= items
.GetCount();
511 void wxListBox::SetString(int N
, const wxString
& s
)
513 wxSizeKeeper
sk( this );
514 Widget listBox
= (Widget
) m_mainWidget
;
516 wxXmString
text( s
);
518 // delete the item and add it again.
519 // FIXME isn't there a way to change it in place?
520 XmListDeletePos (listBox
, N
+1);
521 XmListAddItem (listBox
, text(), N
+1);
526 void wxListBox::Command (wxCommandEvent
& event
)
528 if (event
.m_extraLong
)
529 SetSelection (event
.m_commandInt
);
532 Deselect (event
.m_commandInt
);
535 ProcessCommand (event
);
538 void wxListBoxCallback (Widget
WXUNUSED(w
), XtPointer clientData
,
539 XmListCallbackStruct
* cbs
)
541 wxListBox
*item
= (wxListBox
*) clientData
;
543 if (item
->InSetValue())
548 if( cbs
->reason
== XmCR_DEFAULT_ACTION
)
549 evtType
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
;
551 evtType
= wxEVT_COMMAND_LISTBOX_SELECTED
;
553 int n
= cbs
->item_position
- 1;
554 wxCommandEvent
event (evtType
, item
->GetId());
555 if ( item
->HasClientObjectData() )
556 event
.SetClientObject( item
->GetClientObject(n
) );
557 else if ( item
->HasClientUntypedData() )
558 event
.SetClientData( item
->GetClientData(n
) );
559 event
.m_commandInt
= n
;
560 event
.m_extraLong
= TRUE
;
561 event
.SetEventObject(item
);
562 event
.SetString( item
->GetString( n
) );
565 if( NULL
!= cbs
->event
&& cbs
->event
->type
== ButtonRelease
)
567 XButtonEvent
* evt
= (XButtonEvent
*)cbs
->event
;
574 case XmCR_MULTIPLE_SELECT
:
575 case XmCR_BROWSE_SELECT
:
576 #if wxUSE_CHECKLISTBOX
577 item
->DoToggleItem( n
, x
);
579 case XmCR_DEFAULT_ACTION
:
580 item
->GetEventHandler()->ProcessEvent(event
);
582 case XmCR_EXTENDED_SELECT
:
583 switch (cbs
->selection_type
)
588 item
->DoToggleItem( n
, x
);
589 item
->GetEventHandler()->ProcessEvent(event
);
596 WXWidget
wxListBox::GetTopWidget() const
598 return (WXWidget
) XtParent( (Widget
) m_mainWidget
);
601 void wxListBox::ChangeBackgroundColour()
603 wxWindow::ChangeBackgroundColour();
605 Widget parent
= XtParent ((Widget
) m_mainWidget
);
608 XtVaGetValues (parent
,
609 XmNhorizontalScrollBar
, &hsb
,
610 XmNverticalScrollBar
, &vsb
,
613 /* TODO: should scrollbars be affected? Should probably have separate
614 * function to change them (by default, taken from wxSystemSettings)
616 wxColour backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
617 DoChangeBackgroundColour((WXWidget
) hsb
, backgroundColour
, TRUE
);
618 DoChangeBackgroundColour((WXWidget
) vsb
, backgroundColour
, TRUE
);
621 XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(hsb
)),
624 XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(vsb
)),
627 DoChangeBackgroundColour((WXWidget
) parent
, m_backgroundColour
, TRUE
);
630 void wxListBox::ChangeForegroundColour()
632 wxWindow::ChangeForegroundColour();
634 Widget parent
= XtParent ((Widget
) m_mainWidget
);
637 XtVaGetValues(parent
,
638 XmNhorizontalScrollBar
, &hsb
,
639 XmNverticalScrollBar
, &vsb
,
642 /* TODO: should scrollbars be affected? Should probably have separate
643 function to change them (by default, taken from wxSystemSettings)
645 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
646 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
647 DoChangeForegroundColour((WXWidget) parent, m_foregroundColour);
651 int wxListBox::GetCount() const