1 ///////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "listbox.h"
16 #include "wx/listbox.h"
17 #include "wx/settings.h"
18 #include "wx/dynarray.h"
23 #include "wx/motif/private.h"
25 #if !USE_SHARED_LIBRARY
26 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControl
)
29 void wxListBoxCallback (Widget w
, XtPointer clientData
,
30 XmListCallbackStruct
* cbs
);
32 void wxListBoxDefaultActionProc (Widget list_w
, XtPointer client_data
, XmListCallbackStruct
* cbs
);
34 // ============================================================================
35 // list box control implementation
36 // ============================================================================
39 wxListBox::wxListBox(): m_clientDataList(wxKEY_INTEGER
)
45 bool wxListBox::Create(wxWindow
*parent
, wxWindowID id
,
48 int n
, const wxString choices
[],
50 const wxValidator
& validator
,
53 m_windowStyle
= style
;
56 // m_backgroundColour = parent->GetBackgroundColour();
57 m_backgroundColour
= * wxWHITE
;
58 m_foregroundColour
= parent
->GetForegroundColour();
61 SetValidator(validator
);
63 if (parent
) parent
->AddChild(this);
65 m_windowId
= ( id
== -1 ) ? (int)NewControlId() : id
;
67 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
71 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
72 if (m_windowStyle
& wxLB_MULTIPLE
)
73 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
74 else if (m_windowStyle
& wxLB_EXTENDED
)
75 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
77 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
78 if (m_windowStyle
& wxLB_ALWAYS_SB
)
80 XtSetArg (args
[2], XmNscrollBarDisplayPolicy
, XmSTATIC
);
86 Widget listWidget
= XmCreateScrolledList (parentWidget
, (char*) (const char*) name
, args
, count
);
88 m_mainWidget
= (WXWidget
) listWidget
;
92 XtManageChild (listWidget
);
101 XtAddCallback (listWidget
, XmNbrowseSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
103 XtAddCallback (listWidget
, XmNextendedSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
105 XtAddCallback (listWidget
, XmNmultipleSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
108 XtAddCallback (listWidget
, XmNdefaultActionCallback
, (XtCallbackProc
) wxListBoxDefaultActionProc
,
111 m_windowFont
= parent
->GetFont();
114 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, width
, height
);
116 ChangeBackgroundColour();
121 wxListBox::~wxListBox()
125 void wxListBox::SetFirstItem(int N
)
131 XtVaGetValues ((Widget
) m_mainWidget
,
132 XmNvisibleItemCount
, &count
,
133 XmNitemCount
, &length
,
135 if ((N
+ count
) >= length
)
137 XmListSetPos ((Widget
) m_mainWidget
, N
+ 1);
140 void wxListBox::SetFirstItem(const wxString
& s
)
142 int N
= FindString (s
);
148 void wxListBox::Delete(int N
)
152 Widget listBox
= (Widget
) m_mainWidget
;
153 GetSize (&width1
, &height1
);
155 bool managed
= XtIsManaged(listBox
);
158 XtUnmanageChild (listBox
);
160 XmListDeletePos (listBox
, N
+ 1);
163 XtManageChild (listBox
);
165 GetSize (&width2
, &height2
);
166 // Correct for randomly resized listbox - bad boy, Motif!
167 if (width1
!= width2
|| height1
!= height2
)
168 SetSize (-1, -1, width1
, height1
);
170 // (JDH) need to add code here to take care of clientDataList
171 wxNode
*node
= m_clientDataList
.Find((long)N
); // get item from list
172 if (node
) m_clientDataList
.DeleteNode(node
); // if existed then delete from list
173 node
= m_clientDataList
.First(); // we now have to adjust all keys that
174 while (node
) // are >=N+1
175 { if (node
->GetKeyInteger() >= (long)(N
+1))
176 node
->SetKeyInteger(node
->GetKeyInteger() - 1);
183 void wxListBox::Append(const wxString
& item
)
188 Widget listBox
= (Widget
) m_mainWidget
;
189 GetSize (&width1
, &height1
);
191 bool managed
= XtIsManaged(listBox
);
194 XtUnmanageChild (listBox
);
196 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
197 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
198 // XmListAddItem(listBox, text, n + 1);
199 XmListAddItemUnselected (listBox
, text
, 0);
202 // It seems that if the list is cleared, we must re-ask for
203 // selection policy!!
205 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
206 if (m_windowStyle
& wxLB_MULTIPLE
)
207 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
208 else if (m_windowStyle
& wxLB_EXTENDED
)
209 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
211 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
212 XtSetValues (listBox
, args
, 2);
215 XtManageChild (listBox
);
217 GetSize (&width2
, &height2
);
218 // Correct for randomly resized listbox - bad boy, Motif!
219 if (width1
!= width2
|| height1
!= height2
)
220 SetSize (-1, -1, width1
, height1
);
224 void wxListBox::Append(const wxString
& item
, char *clientData
)
229 Widget listBox
= (Widget
) m_mainWidget
;
231 GetSize (&width1
, &height1
);
232 Bool managed
= XtIsManaged(listBox
);
235 XtUnmanageChild (listBox
);
238 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
239 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
240 // XmListAddItem(listBox, text, n + 1);
241 XmListAddItemUnselected (listBox
, text
, 0);
244 // It seems that if the list is cleared, we must re-ask for
245 // selection policy!!
247 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
248 if (m_windowStyle
& wxLB_MULTIPLE
)
249 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
250 else if (m_windowStyle
& wxLB_EXTENDED
)
251 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
253 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
254 XtSetValues (listBox
, args
, 2);
256 m_clientDataList
.Append ((long) n
, (wxObject
*) clientData
);
259 XtManageChild (listBox
);
261 GetSize (&width2
, &height2
);
263 // Correct for randomly resized listbox - bad boy, Motif!
264 if (width1
!= width2
|| height1
!= height2
)
265 SetSize (-1, -1, width1
, height1
);
270 void wxListBox::Set(int n
, const wxString
*choices
, char** clientData
)
272 m_clientDataList
.Clear();
276 Widget listBox
= (Widget
) m_mainWidget
;
277 GetSize (&width1
, &height1
);
279 bool managed
= XtIsManaged(listBox
);
282 XtUnmanageChild (listBox
);
284 for (int i=0; i<n; i++)
286 XmString text = XmStringCreateSimple(choices[i]);
287 XmListAddItemUnselected(listBox, text, 0);
291 XmString
*text
= new XmString
[n
];
293 for (i
= 0; i
< n
; i
++)
294 text
[i
] = XmStringCreateSimple ((char*) (const char*) choices
[i
]);
297 for (i
= 0; i
< n
; i
++)
298 m_clientDataList
.Append ((long) i
, (wxObject
*) clientData
[i
]);
300 XmListAddItems (listBox
, text
, n
, 0);
301 for (i
= 0; i
< n
; i
++)
302 XmStringFree (text
[i
]);
305 // It seems that if the list is cleared, we must re-ask for
306 // selection policy!!
308 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
309 if (m_windowStyle
& wxLB_MULTIPLE
)
310 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
311 else if (m_windowStyle
& wxLB_EXTENDED
)
312 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
314 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
315 XtSetValues (listBox
, args
, 2);
318 XtManageChild (listBox
);
320 GetSize (&width2
, &height2
);
321 // Correct for randomly resized listbox - bad boy, Motif!
322 if (width1
!= width2
|| height1
!= height2
)
323 SetSize (-1, -1, width1
, height1
);
328 int wxListBox::FindString(const wxString
& s
) const
330 XmString str
= XmStringCreateSimple ((char*) (const char*) s
);
331 int *positions
= NULL
;
332 int no_positions
= 0;
333 bool success
= XmListGetMatchPos ((Widget
) m_mainWidget
, str
, &positions
, &no_positions
);
337 int pos
= positions
[0];
339 XtFree ((char *) positions
);
346 void wxListBox::Clear()
354 Widget listBox
= (Widget
) m_mainWidget
;
355 GetSize (&width1
, &height1
);
357 XmListDeleteAllItems (listBox
);
358 m_clientDataList
.Clear ();
359 GetSize (&width2
, &height2
);
361 // Correct for randomly resized listbox - bad boy, Motif!
362 if (width1
!= width2
|| height1
!= height2
)
363 SetSize (-1, -1, width1
, height1
);
368 void wxListBox::SetSelection(int N
, bool select
)
374 if (m_windowStyle & wxLB_MULTIPLE)
376 int *selections = NULL;
377 int n = GetSelections (&selections);
379 // This hack is supposed to work, to make it possible to select more
380 // than one item, but it DOESN'T under Motif 1.1.
382 XtVaSetValues ((Widget) m_mainWidget, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
385 for (i = 0; i < n; i++)
386 XmListSelectPos ((Widget) m_mainWidget, selections[i] + 1, FALSE);
388 XmListSelectPos ((Widget) m_mainWidget, N + 1, FALSE);
390 XtVaSetValues ((Widget) m_mainWidget, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
394 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
398 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
400 m_inSetValue
= FALSE
;
403 bool wxListBox::Selected(int N
) const
405 // In Motif, no simple way to determine if the item is selected.
406 wxArrayInt theSelections
;
407 int count
= GetSelections (theSelections
);
413 for (j
= 0; j
< count
; j
++)
414 if (theSelections
[j
] == N
)
420 void wxListBox::Deselect(int N
)
422 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
425 char *wxListBox::GetClientData(int N
) const
427 wxNode
*node
= m_clientDataList
.Find ((long) N
);
429 return (char *) node
->Data ();
434 void wxListBox::SetClientData(int N
, char *Client_data
)
436 wxNode
*node
= m_clientDataList
.Find ((long) N
);
438 node
->SetData ((wxObject
*)Client_data
);
440 node
= m_clientDataList
.Append((long) N
, (wxObject
*) Client_data
);
443 // Return number of selections and an array of selected integers
444 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const
448 Widget listBox
= (Widget
) m_mainWidget
;
451 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
456 aSelections
.Alloc(posCnt
);
459 for (i
= 0; i
< posCnt
; i
++)
460 aSelections
.Add(posList
[i
] - 1);
462 XtFree ((char *) posList
);
472 // Get single selection, for single choice list items
473 int wxListBox::GetSelection() const
475 Widget listBox
= (Widget
) m_mainWidget
;
478 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
484 XtFree ((char *) posList
);
491 // Find string for position
492 wxString
wxListBox::GetString(int N
) const
494 Widget listBox
= (Widget
) m_mainWidget
;
497 XtVaGetValues (listBox
, XmNitemCount
, &n
, XmNitems
, &strlist
, NULL
);
498 if (N
<= n
&& N
>= 0)
501 if (XmStringGetLtoR (strlist
[N
], XmSTRING_DEFAULT_CHARSET
, &txt
))
508 return wxEmptyString
;
511 return wxEmptyString
;
514 void wxListBox::SetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
516 wxWindow::SetSize(x
, y
, width
, height
, sizeFlags
);
518 // Check resulting size is correct
520 GetSize (&tempW
, &tempH
);
523 if (tempW != width || tempH != height)
525 cout << "wxListBox::SetSize sizes not set correctly.");
530 void wxListBox::InsertItems(int nItems
, const wxString items
[], int pos
)
535 Widget listBox
= (Widget
) m_mainWidget
;
537 GetSize(&width1
, &height1
);
539 bool managed
= XtIsManaged(listBox
);
542 XtUnmanageChild(listBox
);
544 XmString
*text
= new XmString
[nItems
];
546 // Steve Hammes: Motif 1.1 compatibility
547 // #if XmVersion > 1100
548 // Corrected by Sergey Krasnov from Steve Hammes' code
550 for (i
= 0; i
< nItems
; i
++)
551 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
552 XmListAddItemsUnselected(listBox
, text
, nItems
, pos
+1);
554 for (i
= 0; i
< nItems
; i
++)
556 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
557 // XmListAddItemUnselected(listBox, text[i], i);
558 XmListAddItemUnselected(listBox
, text
[i
], pos
+i
+1); // Another Sergey correction
561 for (i
= 0; i
< nItems
; i
++)
562 XmStringFree(text
[i
]);
566 // It seems that if the list is cleared, we must re-ask for
567 // selection policy!!
569 XtSetArg(args
[0], XmNlistSizePolicy
, XmCONSTANT
);
570 if (m_windowStyle
& wxLB_MULTIPLE
)
571 XtSetArg(args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
572 else if (m_windowStyle
& wxLB_EXTENDED
)
573 XtSetArg(args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
574 else XtSetArg(args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
575 XtSetValues(listBox
,args
,2) ;
578 XtManageChild(listBox
);
580 GetSize(&width2
, &height2
);
581 // Correct for randomly resized listbox - bad boy, Motif!
582 if (width1
!= width2
/*|| height1 != height2*/)
583 SetSize(-1, -1, width1
, height1
);
588 void wxListBox::SetString(int N
, const wxString
& s
)
593 Widget listBox
= (Widget
) m_mainWidget
;
594 GetSize (&width1
, &height1
);
596 XmString text
= XmStringCreateSimple ((char*) (const char*) s
);
598 // WHAT'S THE MOTIF CALL TO SET THE TEXT OF AN EXISTING
600 // There isn't one, so delete the item and add it again.
601 XmListDeletePos (listBox
, N
+1);
602 XmListAddItem (listBox
, text
, N
+1);
607 // It seems that if the list is cleared, we must re-ask for
608 // selection policy!!
610 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
611 if (m_windowStyle & wxLB_MULTIPLE)
612 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
613 else if (m_windowStyle & wxLB_EXTENDED)
614 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
616 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
617 XtSetValues (listBox, args, 2);
620 GetSize (&width2
, &height2
);
621 // Correct for randomly resized listbox - bad boy, Motif!
622 if (width1
!= width2
|| height1
!= height2
)
623 SetSize (-1, -1, width1
, height1
);
626 int wxListBox::Number () const
631 // For single selection items only
632 wxString
wxListBox::GetStringSelection () const
634 int sel
= GetSelection ();
636 return this->GetString (sel
);
641 bool wxListBox::SetStringSelection (const wxString
& s
, bool flag
)
643 int sel
= FindString (s
);
646 SetSelection (sel
, flag
);
653 void wxListBox::Command (wxCommandEvent
& event
)
655 if (event
.m_extraLong
)
656 SetSelection (event
.m_commandInt
);
659 Deselect (event
.m_commandInt
);
662 ProcessCommand (event
);
665 void wxListBoxCallback (Widget w
, XtPointer clientData
,
666 XmListCallbackStruct
* cbs
)
669 if (cbs->reason == XmCR_EXTENDED_SELECT)
670 cout << "*** Extend select\n";
671 else if (cbs->reason == XmCR_SINGLE_SELECT)
672 cout << "*** Single select\n";
673 else if (cbs->reason == XmCR_MULTIPLE_SELECT)
674 cout << "*** Multiple select\n";
675 else if (cbs->reason == XmCR_BROWSE_SELECT)
676 cout << "*** Browse select\n";
678 if (cbs->selection_type == XmMODIFICATION)
679 cout << "*** Modification\n";
680 else if (cbs->selection_type == XmINITIAL)
681 cout << "*** Initial\n";
682 else if (cbs->selection_type == XmADDITION)
683 cout << "*** Addition\n";
686 wxListBox
*item
= (wxListBox
*) clientData
;
688 if (item
->InSetValue())
691 wxCommandEvent
event (wxEVT_COMMAND_LISTBOX_SELECTED
, item
->GetId());
694 case XmCR_MULTIPLE_SELECT
:
695 case XmCR_BROWSE_SELECT
:
697 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
698 //event.commandString = item->GetStringSelection();
699 event
.m_commandInt
= cbs
->item_position
- 1;
700 event
.m_extraLong
= TRUE
;
701 event
.SetEventObject(item
);
702 item
->ProcessCommand (event
);
703 //delete[] event.commandString; // Let's not store the command string any more
706 case XmCR_EXTENDED_SELECT
:
708 switch (cbs
->selection_type
)
714 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
715 event
.m_commandInt
= cbs
->item_position
- 1;
716 event
.m_extraLong
= TRUE
;
717 event
.SetEventObject(item
);
718 item
->ProcessCommand (event
);
727 /* Respond by getting the
728 * designated "default button" in the action area and activate it
729 * as if the user had selected it.
731 void wxListBoxDefaultActionProc (Widget list_w
, XtPointer client_data
, XmListCallbackStruct
* cbs
)
733 wxListBox
*lbox
= (wxListBox
*) client_data
;
735 wxCommandEvent
event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
, lbox
->GetId());
736 event
.SetEventObject( lbox
);
737 lbox
->GetEventHandler()->ProcessEvent(event
) ;
740 WXWidget
wxListBox::GetTopWidget() const
742 return (WXWidget
) XtParent( (Widget
) m_mainWidget
);
745 void wxListBox::ChangeFont(bool keepOriginalSize
)
747 wxWindow::ChangeFont(keepOriginalSize
);
750 void wxListBox::ChangeBackgroundColour()
752 wxWindow::ChangeBackgroundColour();
754 Widget parent
= XtParent ((Widget
) m_mainWidget
);
757 XtVaGetValues (parent
,
758 XmNhorizontalScrollBar
, &hsb
,
759 XmNverticalScrollBar
, &vsb
,
762 /* TODO: should scrollbars be affected? Should probably have separate
763 * function to change them (by default, taken from wxSystemSettings)
765 wxColour backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
);
766 DoChangeBackgroundColour((WXWidget
) hsb
, backgroundColour
, TRUE
);
767 DoChangeBackgroundColour((WXWidget
) vsb
, backgroundColour
, TRUE
);
769 DoChangeBackgroundColour((WXWidget
) parent
, m_backgroundColour
, TRUE
);
772 void wxListBox::ChangeForegroundColour()
774 wxWindow::ChangeForegroundColour();
776 Widget parent
= XtParent ((Widget
) m_mainWidget
);
779 XtVaGetValues (parent
,
780 XmNhorizontalScrollBar
, &hsb
,
781 XmNverticalScrollBar
, &vsb
,
783 /* TODO: should scrollbars be affected? Should probably have separate
784 * function to change them (by default, taken from wxSystemSettings)
785 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
786 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
787 DoChangeForegroundColour((WXWidget) parent, m_foregroundColour);