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 // ============================================================================
43 // list box control implementation
44 // ============================================================================
47 wxListBox::wxListBox() : m_clientDataList(wxKEY_INTEGER
)
52 bool wxListBox::Create(wxWindow
*parent
, wxWindowID id
,
55 int n
, const wxString choices
[],
57 const wxValidator
& validator
,
60 m_windowStyle
= style
;
62 // m_backgroundColour = parent->GetBackgroundColour();
63 m_backgroundColour
= * wxWHITE
;
64 m_foregroundColour
= parent
->GetForegroundColour();
67 SetValidator(validator
);
69 if (parent
) parent
->AddChild(this);
71 m_windowId
= ( id
== -1 ) ? (int)NewControlId() : id
;
73 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
77 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
78 if (m_windowStyle
& wxLB_MULTIPLE
)
79 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
80 else if (m_windowStyle
& wxLB_EXTENDED
)
81 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
83 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
84 if (m_windowStyle
& wxLB_ALWAYS_SB
)
86 XtSetArg (args
[2], XmNscrollBarDisplayPolicy
, XmSTATIC
);
92 Widget listWidget
= XmCreateScrolledList(parentWidget
,
93 (char*)name
.c_str(), args
, count
);
95 m_mainWidget
= (WXWidget
) listWidget
;
99 XtManageChild (listWidget
);
102 long height
= size
.y
;
108 XtAddCallback (listWidget
,
109 XmNbrowseSelectionCallback
,
110 (XtCallbackProc
) wxListBoxCallback
,
112 XtAddCallback (listWidget
,
113 XmNextendedSelectionCallback
,
114 (XtCallbackProc
) wxListBoxCallback
,
116 XtAddCallback (listWidget
,
117 XmNmultipleSelectionCallback
,
118 (XtCallbackProc
) wxListBoxCallback
,
120 XtAddCallback (listWidget
,
121 XmNdefaultActionCallback
,
122 (XtCallbackProc
) wxListBoxCallback
,
125 m_font
= parent
->GetFont();
128 SetCanAddEventHandler(TRUE
);
129 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
,
130 pos
.x
, pos
.y
, width
, height
);
132 ChangeBackgroundColour();
137 wxListBox::~wxListBox()
141 void wxListBox::DoSetFirstItem( int N
)
147 XtVaGetValues ((Widget
) m_mainWidget
,
148 XmNvisibleItemCount
, &count
,
149 XmNitemCount
, &length
,
151 if ((N
+ count
) >= length
)
153 XmListSetPos ((Widget
) m_mainWidget
, N
+ 1);
156 void wxListBox::Delete(int N
)
160 Widget listBox
= (Widget
) m_mainWidget
;
161 GetSize (&width1
, &height1
);
163 bool managed
= XtIsManaged(listBox
);
166 XtUnmanageChild (listBox
);
168 XmListDeletePos (listBox
, N
+ 1);
171 XtManageChild (listBox
);
173 GetSize (&width2
, &height2
);
174 // Correct for randomly resized listbox - bad boy, Motif!
175 if (width1
!= width2
|| height1
!= height2
)
176 SetSize (-1, -1, width1
, height1
);
178 // (JDH) need to add code here to take care of clientDataList
179 // get item from list
180 wxNode
*node
= m_clientDataList
.Find((long)N
);
181 // if existed then delete from list
182 if (node
) m_clientDataList
.DeleteNode(node
);
183 // we now have to adjust all keys that are >=N+1
184 node
= m_clientDataList
.First();
187 if (node
->GetKeyInteger() >= (long)(N
+1))
188 node
->SetKeyInteger(node
->GetKeyInteger() - 1);
195 int wxListBox::DoAppend(const wxString
& item
)
200 Widget listBox
= (Widget
) m_mainWidget
;
201 GetSize (&width1
, &height1
);
203 bool managed
= XtIsManaged(listBox
);
206 XtUnmanageChild (listBox
);
208 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
209 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
210 // XmListAddItem(listBox, text, n + 1);
211 XmListAddItemUnselected (listBox
, text
, 0);
214 // It seems that if the list is cleared, we must re-ask for
215 // selection policy!!
217 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
218 if (m_windowStyle
& wxLB_MULTIPLE
)
219 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
220 else if (m_windowStyle
& wxLB_EXTENDED
)
221 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
223 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
224 XtSetValues (listBox
, args
, 2);
227 XtManageChild (listBox
);
229 GetSize (&width2
, &height2
);
230 // Correct for randomly resized listbox - bad boy, Motif!
231 if (width1
!= width2
|| height1
!= height2
)
232 SetSize (-1, -1, width1
, height1
);
235 return GetCount() - 1;
238 void wxListBox::DoSetItems(const wxArrayString
& items
, void** clientData
)
240 m_clientDataList
.Clear();
244 Widget listBox
= (Widget
) m_mainWidget
;
245 GetSize (&width1
, &height1
);
247 bool managed
= XtIsManaged(listBox
);
250 XtUnmanageChild (listBox
);
251 XmString
*text
= new XmString
[items
.GetCount()];
253 for (i
= 0; i
< items
.GetCount(); ++i
)
254 text
[i
] = XmStringCreateSimple ((char*)items
[i
].c_str());
257 for (i
= 0; i
< items
.GetCount(); ++i
)
258 m_clientDataList
.Append ((long) i
, (wxObject
*) clientData
[i
]);
260 XmListAddItems (listBox
, text
, items
.GetCount(), 0);
261 for (i
= 0; i
< items
.GetCount(); i
++)
262 XmStringFree (text
[i
]);
265 // It seems that if the list is cleared, we must re-ask for
266 // selection policy!!
268 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
269 if (m_windowStyle
& wxLB_MULTIPLE
)
270 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
271 else if (m_windowStyle
& wxLB_EXTENDED
)
272 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
274 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
275 XtSetValues (listBox
, args
, 2);
278 XtManageChild (listBox
);
280 GetSize (&width2
, &height2
);
281 // Correct for randomly resized listbox - bad boy, Motif!
282 if (width1
!= width2
|| height1
!= height2
)
283 SetSize (-1, -1, width1
, height1
);
285 m_noItems
= items
.GetCount();
288 int wxListBox::FindString(const wxString
& s
) const
290 XmString str
= XmStringCreateSimple ((char*) (const char*) s
);
291 int *positions
= NULL
;
292 int no_positions
= 0;
293 bool success
= XmListGetMatchPos ((Widget
) m_mainWidget
, str
,
294 &positions
, &no_positions
);
298 int pos
= positions
[0];
300 XtFree ((char *) positions
);
307 void wxListBox::Clear()
315 Widget listBox
= (Widget
) m_mainWidget
;
316 GetSize (&width1
, &height1
);
318 XmListDeleteAllItems (listBox
);
319 m_clientDataList
.Clear ();
320 GetSize (&width2
, &height2
);
322 // Correct for randomly resized listbox - bad boy, Motif!
323 if (width1
!= width2
|| height1
!= height2
)
324 SetSize (-1, -1, width1
, height1
);
329 void wxListBox::SetSelection(int N
, bool select
)
335 if (m_windowStyle
& wxLB_MULTIPLE
)
337 int *selections
= NULL
;
338 int n
= GetSelections (&selections
);
340 // This hack is supposed to work, to make it possible
341 // to select more than one item, but it DOESN'T under Motif 1.1.
343 XtVaSetValues ((Widget
) m_mainWidget
,
344 XmNselectionPolicy
, XmMULTIPLE_SELECT
,
348 for (i
= 0; i
< n
; i
++)
349 XmListSelectPos ((Widget
) m_mainWidget
,
350 selections
[i
] + 1, FALSE
);
352 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
354 XtVaSetValues ((Widget
) m_mainWidget
,
355 XmNselectionPolicy
, XmEXTENDED_SELECT
,
360 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
364 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
366 m_inSetValue
= FALSE
;
369 bool wxListBox::IsSelected(int N
) const
371 // In Motif, no simple way to determine if the item is selected.
372 wxArrayInt theSelections
;
373 int count
= GetSelections (theSelections
);
379 for (j
= 0; j
< count
; j
++)
380 if (theSelections
[j
] == N
)
386 void wxListBox::DoSetItemClientObject(int n
, wxClientData
* clientData
)
388 DoSetItemClientData(n
, (void*) clientData
);
391 wxClientData
* wxListBox::DoGetItemClientObject(int n
) const
393 return (wxClientData
*) DoGetItemClientData(n
);
396 void *wxListBox::DoGetItemClientData(int N
) const
398 wxNode
*node
= m_clientDataList
.Find ((long) N
);
400 return (void *) node
->Data ();
405 void wxListBox::DoSetItemClientData(int N
, void *Client_data
)
407 wxNode
*node
= m_clientDataList
.Find ((long) N
);
409 node
->SetData ((wxObject
*)Client_data
);
411 node
= m_clientDataList
.Append((long) N
, (wxObject
*) Client_data
);
414 // Return number of selections and an array of selected integers
415 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const
419 Widget listBox
= (Widget
) m_mainWidget
;
422 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
427 aSelections
.Alloc(posCnt
);
430 for (i
= 0; i
< posCnt
; i
++)
431 aSelections
.Add(posList
[i
] - 1);
433 XtFree ((char *) posList
);
443 // Get single selection, for single choice list items
444 int wxListBox::GetSelection() const
446 Widget listBox
= (Widget
) m_mainWidget
;
449 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
455 XtFree ((char *) posList
);
462 // Find string for position
463 wxString
wxListBox::GetString(int N
) const
465 Widget listBox
= (Widget
) m_mainWidget
;
468 XtVaGetValues (listBox
, XmNitemCount
, &n
, XmNitems
, &strlist
, NULL
);
469 if (N
<= n
&& N
>= 0)
472 if (XmStringGetLtoR (strlist
[N
], XmSTRING_DEFAULT_CHARSET
, &txt
))
479 return wxEmptyString
;
482 return wxEmptyString
;
485 void wxListBox::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
487 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
489 // Check resulting size is correct
491 GetSize (&tempW
, &tempH
);
494 if (tempW != width || tempH != height)
496 cout << "wxListBox::SetSize sizes not set correctly.");
501 void wxListBox::DoInsertItems(const wxArrayString
& items
, int pos
)
506 Widget listBox
= (Widget
) m_mainWidget
;
508 GetSize(&width1
, &height1
);
510 bool managed
= XtIsManaged(listBox
);
513 XtUnmanageChild(listBox
);
515 XmString
*text
= new XmString
[items
.GetCount()];
517 // Steve Hammes: Motif 1.1 compatibility
518 // #if XmVersion > 1100
519 // Corrected by Sergey Krasnov from Steve Hammes' code
521 for (i
= 0; i
< items
.GetCount(); i
++)
522 text
[i
] = XmStringCreateSimple((char*)items
[i
].c_str());
523 XmListAddItemsUnselected(listBox
, text
, items
.GetCount(), pos
+1);
525 for (i
= 0; i
< items
.GetCount(); i
++)
527 text
[i
] = XmStringCreateSimple((char*)items
[i
].c_str());
528 // Another Sergey correction
529 XmListAddItemUnselected(listBox
, text
[i
], pos
+i
+1);
532 for (i
= 0; i
< items
.GetCount(); i
++)
533 XmStringFree(text
[i
]);
536 // It seems that if the list is cleared, we must re-ask for
537 // selection policy!!
539 XtSetArg(args
[0], XmNlistSizePolicy
, XmCONSTANT
);
540 if (m_windowStyle
& wxLB_MULTIPLE
)
541 XtSetArg(args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
542 else if (m_windowStyle
& wxLB_EXTENDED
)
543 XtSetArg(args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
544 else XtSetArg(args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
545 XtSetValues(listBox
,args
,2) ;
548 XtManageChild(listBox
);
550 GetSize(&width2
, &height2
);
551 // Correct for randomly resized listbox - bad boy, Motif!
552 if (width1
!= width2
/*|| height1 != height2*/)
553 SetSize(-1, -1, width1
, height1
);
555 m_noItems
+= items
.GetCount();
558 void wxListBox::SetString(int N
, const wxString
& s
)
563 Widget listBox
= (Widget
) m_mainWidget
;
564 GetSize (&width1
, &height1
);
566 XmString text
= XmStringCreateSimple ((char*) (const char*) s
);
568 // delete the item and add it again.
569 // FIXME isn't there a way to change it in place?
570 XmListDeletePos (listBox
, N
+1);
571 XmListAddItem (listBox
, text
, N
+1);
575 GetSize (&width2
, &height2
);
576 // Correct for randomly resized listbox - bad boy, Motif!
577 if (width1
!= width2
|| height1
!= height2
)
578 SetSize (-1, -1, width1
, height1
);
581 void wxListBox::Command (wxCommandEvent
& event
)
583 if (event
.m_extraLong
)
584 SetSelection (event
.m_commandInt
);
587 Deselect (event
.m_commandInt
);
590 ProcessCommand (event
);
593 void wxListBoxCallback (Widget
WXUNUSED(w
), XtPointer clientData
,
594 XmListCallbackStruct
* cbs
)
596 wxListBox
*item
= (wxListBox
*) clientData
;
598 if (item
->InSetValue())
603 if( cbs
->reason
== XmCR_DEFAULT_ACTION
)
604 evtType
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
;
606 evtType
= wxEVT_COMMAND_LISTBOX_SELECTED
;
608 int n
= cbs
->item_position
- 1;
609 wxCommandEvent
event (evtType
, item
->GetId());
610 if ( item
->HasClientObjectData() )
611 event
.SetClientObject( item
->GetClientObject(n
) );
612 else if ( item
->HasClientUntypedData() )
613 event
.SetClientData( item
->GetClientData(n
) );
614 event
.m_commandInt
= n
;
615 event
.m_extraLong
= TRUE
;
616 event
.SetEventObject(item
);
617 event
.SetString( item
->GetString( n
) );
620 if( cbs
->event
->type
== ButtonRelease
)
622 XButtonEvent
* evt
= (XButtonEvent
*)cbs
->event
;
629 case XmCR_MULTIPLE_SELECT
:
630 case XmCR_BROWSE_SELECT
:
631 #if wxUSE_CHECKLISTBOX
632 item
->DoToggleItem( n
, x
);
634 case XmCR_DEFAULT_ACTION
:
635 item
->GetEventHandler()->ProcessEvent(event
);
637 case XmCR_EXTENDED_SELECT
:
638 switch (cbs
->selection_type
)
643 item
->DoToggleItem( n
, x
);
644 item
->GetEventHandler()->ProcessEvent(event
);
651 WXWidget
wxListBox::GetTopWidget() const
653 return (WXWidget
) XtParent( (Widget
) m_mainWidget
);
656 void wxListBox::ChangeFont(bool keepOriginalSize
)
658 wxWindow::ChangeFont(keepOriginalSize
);
661 void wxListBox::ChangeBackgroundColour()
663 wxWindow::ChangeBackgroundColour();
665 Widget parent
= XtParent ((Widget
) m_mainWidget
);
668 XtVaGetValues (parent
,
669 XmNhorizontalScrollBar
, &hsb
,
670 XmNverticalScrollBar
, &vsb
,
673 /* TODO: should scrollbars be affected? Should probably have separate
674 * function to change them (by default, taken from wxSystemSettings)
676 wxColour backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
677 DoChangeBackgroundColour((WXWidget
) hsb
, backgroundColour
, TRUE
);
678 DoChangeBackgroundColour((WXWidget
) vsb
, backgroundColour
, TRUE
);
681 XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(hsb
)),
684 XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(vsb
)),
687 DoChangeBackgroundColour((WXWidget
) parent
, m_backgroundColour
, TRUE
);
690 void wxListBox::ChangeForegroundColour()
692 wxWindow::ChangeForegroundColour();
694 Widget parent
= XtParent ((Widget
) m_mainWidget
);
697 XtVaGetValues(parent
,
698 XmNhorizontalScrollBar
, &hsb
,
699 XmNverticalScrollBar
, &vsb
,
702 /* TODO: should scrollbars be affected? Should probably have separate
703 function to change them (by default, taken from wxSystemSettings)
705 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
706 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
707 DoChangeForegroundColour((WXWidget) parent, m_foregroundColour);
711 int wxListBox::GetCount() const