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 #pragma message disable nosimpint
27 #pragma message enable nosimpint
29 #include "wx/motif/private.h"
31 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControl
)
33 static void wxListBoxCallback(Widget w
,
35 XmListCallbackStruct
* cbs
);
37 static void wxListBoxDefaultActionProc(Widget list_w
,
38 XtPointer client_data
,
39 XmListCallbackStruct
* cbs
);
41 // ============================================================================
42 // list box control implementation
43 // ============================================================================
46 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
;
63 // m_backgroundColour = parent->GetBackgroundColour();
64 m_backgroundColour
= * wxWHITE
;
65 m_foregroundColour
= parent
->GetForegroundColour();
68 SetValidator(validator
);
70 if (parent
) parent
->AddChild(this);
72 m_windowId
= ( id
== -1 ) ? (int)NewControlId() : id
;
74 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
78 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
79 if (m_windowStyle
& wxLB_MULTIPLE
)
80 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
81 else if (m_windowStyle
& wxLB_EXTENDED
)
82 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
84 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
85 if (m_windowStyle
& wxLB_ALWAYS_SB
)
87 XtSetArg (args
[2], XmNscrollBarDisplayPolicy
, XmSTATIC
);
93 Widget listWidget
= XmCreateScrolledList (parentWidget
, (char*) (const char*) name
, args
, count
);
95 m_mainWidget
= (WXWidget
) listWidget
;
99 XtManageChild (listWidget
);
102 long height
= size
.y
;
108 XtAddCallback (listWidget
, XmNbrowseSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
110 XtAddCallback (listWidget
, XmNextendedSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
112 XtAddCallback (listWidget
, XmNmultipleSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
115 XtAddCallback (listWidget
, XmNdefaultActionCallback
, (XtCallbackProc
) wxListBoxDefaultActionProc
,
118 m_font
= parent
->GetFont();
121 SetCanAddEventHandler(TRUE
);
122 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, width
, height
);
124 ChangeBackgroundColour();
129 wxListBox::~wxListBox()
133 void wxListBox::SetFirstItem(int N
)
139 XtVaGetValues ((Widget
) m_mainWidget
,
140 XmNvisibleItemCount
, &count
,
141 XmNitemCount
, &length
,
143 if ((N
+ count
) >= length
)
145 XmListSetPos ((Widget
) m_mainWidget
, N
+ 1);
148 void wxListBox::SetFirstItem(const wxString
& s
)
150 int N
= FindString (s
);
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 wxNode
*node
= m_clientDataList
.Find((long)N
); // get item from list
180 if (node
) m_clientDataList
.DeleteNode(node
); // if existed then delete from list
181 node
= m_clientDataList
.First(); // we now have to adjust all keys that
182 while (node
) // are >=N+1
184 if (node
->GetKeyInteger() >= (long)(N
+1))
185 node
->SetKeyInteger(node
->GetKeyInteger() - 1);
192 void wxListBox::Append(const wxString
& item
)
197 Widget listBox
= (Widget
) m_mainWidget
;
198 GetSize (&width1
, &height1
);
200 bool managed
= XtIsManaged(listBox
);
203 XtUnmanageChild (listBox
);
205 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
206 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
207 // XmListAddItem(listBox, text, n + 1);
208 XmListAddItemUnselected (listBox
, text
, 0);
211 // It seems that if the list is cleared, we must re-ask for
212 // selection policy!!
214 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
215 if (m_windowStyle
& wxLB_MULTIPLE
)
216 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
217 else if (m_windowStyle
& wxLB_EXTENDED
)
218 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
220 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
221 XtSetValues (listBox
, args
, 2);
224 XtManageChild (listBox
);
226 GetSize (&width2
, &height2
);
227 // Correct for randomly resized listbox - bad boy, Motif!
228 if (width1
!= width2
|| height1
!= height2
)
229 SetSize (-1, -1, width1
, height1
);
233 void wxListBox::Append(const wxString
& item
, void *clientData
)
238 Widget listBox
= (Widget
) m_mainWidget
;
240 GetSize (&width1
, &height1
);
241 Bool managed
= XtIsManaged(listBox
);
244 XtUnmanageChild (listBox
);
247 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
248 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
249 // XmListAddItem(listBox, text, n + 1);
250 XmListAddItemUnselected (listBox
, text
, 0);
253 // It seems that if the list is cleared, we must re-ask for
254 // selection policy!!
256 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
257 if (m_windowStyle
& wxLB_MULTIPLE
)
258 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
259 else if (m_windowStyle
& wxLB_EXTENDED
)
260 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
262 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
263 XtSetValues (listBox
, args
, 2);
265 m_clientDataList
.Append ((long) n
, (wxObject
*) clientData
);
268 XtManageChild (listBox
);
270 GetSize (&width2
, &height2
);
272 // Correct for randomly resized listbox - bad boy, Motif!
273 if (width1
!= width2
|| height1
!= height2
)
274 SetSize (-1, -1, width1
, height1
);
279 void wxListBox::Set(int n
, const wxString
*choices
, void** clientData
)
281 m_clientDataList
.Clear();
285 Widget listBox
= (Widget
) m_mainWidget
;
286 GetSize (&width1
, &height1
);
288 bool managed
= XtIsManaged(listBox
);
291 XtUnmanageChild (listBox
);
293 for (int i=0; i<n; i++)
295 XmString text = XmStringCreateSimple(choices[i]);
296 XmListAddItemUnselected(listBox, text, 0);
300 XmString
*text
= new XmString
[n
];
302 for (i
= 0; i
< n
; i
++)
303 text
[i
] = XmStringCreateSimple ((char*) (const char*) choices
[i
]);
306 for (i
= 0; i
< n
; i
++)
307 m_clientDataList
.Append ((long) i
, (wxObject
*) clientData
[i
]);
309 XmListAddItems (listBox
, text
, n
, 0);
310 for (i
= 0; i
< n
; i
++)
311 XmStringFree (text
[i
]);
314 // It seems that if the list is cleared, we must re-ask for
315 // selection policy!!
317 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
318 if (m_windowStyle
& wxLB_MULTIPLE
)
319 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
320 else if (m_windowStyle
& wxLB_EXTENDED
)
321 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
323 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
324 XtSetValues (listBox
, args
, 2);
327 XtManageChild (listBox
);
329 GetSize (&width2
, &height2
);
330 // Correct for randomly resized listbox - bad boy, Motif!
331 if (width1
!= width2
|| height1
!= height2
)
332 SetSize (-1, -1, width1
, height1
);
337 int wxListBox::FindString(const wxString
& s
) const
339 XmString str
= XmStringCreateSimple ((char*) (const char*) s
);
340 int *positions
= NULL
;
341 int no_positions
= 0;
342 bool success
= XmListGetMatchPos ((Widget
) m_mainWidget
, str
, &positions
, &no_positions
);
346 int pos
= positions
[0];
348 XtFree ((char *) positions
);
355 void wxListBox::Clear()
363 Widget listBox
= (Widget
) m_mainWidget
;
364 GetSize (&width1
, &height1
);
366 XmListDeleteAllItems (listBox
);
367 m_clientDataList
.Clear ();
368 GetSize (&width2
, &height2
);
370 // Correct for randomly resized listbox - bad boy, Motif!
371 if (width1
!= width2
|| height1
!= height2
)
372 SetSize (-1, -1, width1
, height1
);
377 void wxListBox::SetSelection(int N
, bool select
)
383 if (m_windowStyle
& wxLB_MULTIPLE
)
385 int *selections
= NULL
;
386 int n
= GetSelections (&selections
);
388 // This hack is supposed to work, to make it possible to select more
389 // than one item, but it DOESN'T under Motif 1.1.
391 XtVaSetValues ((Widget
) m_mainWidget
, XmNselectionPolicy
, XmMULTIPLE_SELECT
, NULL
);
394 for (i
= 0; i
< n
; i
++)
395 XmListSelectPos ((Widget
) m_mainWidget
, selections
[i
] + 1, FALSE
);
397 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
399 XtVaSetValues ((Widget
) m_mainWidget
, XmNselectionPolicy
, XmEXTENDED_SELECT
, NULL
);
403 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
407 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
409 m_inSetValue
= FALSE
;
412 bool wxListBox::Selected(int N
) const
414 // In Motif, no simple way to determine if the item is selected.
415 wxArrayInt theSelections
;
416 int count
= GetSelections (theSelections
);
422 for (j
= 0; j
< count
; j
++)
423 if (theSelections
[j
] == N
)
429 void wxListBox::Deselect(int N
)
431 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
434 void *wxListBox::GetClientData(int N
) const
436 wxNode
*node
= m_clientDataList
.Find ((long) N
);
438 return (void *) node
->Data ();
443 void wxListBox::SetClientData(int N
, void *Client_data
)
445 wxNode
*node
= m_clientDataList
.Find ((long) N
);
447 node
->SetData ((wxObject
*)Client_data
);
449 node
= m_clientDataList
.Append((long) N
, (wxObject
*) Client_data
);
452 // Return number of selections and an array of selected integers
453 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const
457 Widget listBox
= (Widget
) m_mainWidget
;
460 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
465 aSelections
.Alloc(posCnt
);
468 for (i
= 0; i
< posCnt
; i
++)
469 aSelections
.Add(posList
[i
] - 1);
471 XtFree ((char *) posList
);
481 // Get single selection, for single choice list items
482 int wxListBox::GetSelection() const
484 Widget listBox
= (Widget
) m_mainWidget
;
487 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
493 XtFree ((char *) posList
);
500 // Find string for position
501 wxString
wxListBox::GetString(int N
) const
503 Widget listBox
= (Widget
) m_mainWidget
;
506 XtVaGetValues (listBox
, XmNitemCount
, &n
, XmNitems
, &strlist
, NULL
);
507 if (N
<= n
&& N
>= 0)
510 if (XmStringGetLtoR (strlist
[N
], XmSTRING_DEFAULT_CHARSET
, &txt
))
517 return wxEmptyString
;
520 return wxEmptyString
;
523 void wxListBox::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
525 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
527 // Check resulting size is correct
529 GetSize (&tempW
, &tempH
);
532 if (tempW != width || tempH != height)
534 cout << "wxListBox::SetSize sizes not set correctly.");
539 void wxListBox::InsertItems(int nItems
, const wxString items
[], int pos
)
544 Widget listBox
= (Widget
) m_mainWidget
;
546 GetSize(&width1
, &height1
);
548 bool managed
= XtIsManaged(listBox
);
551 XtUnmanageChild(listBox
);
553 XmString
*text
= new XmString
[nItems
];
555 // Steve Hammes: Motif 1.1 compatibility
556 // #if XmVersion > 1100
557 // Corrected by Sergey Krasnov from Steve Hammes' code
559 for (i
= 0; i
< nItems
; i
++)
560 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
561 XmListAddItemsUnselected(listBox
, text
, nItems
, pos
+1);
563 for (i
= 0; i
< nItems
; i
++)
565 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
566 // XmListAddItemUnselected(listBox, text[i], i);
567 XmListAddItemUnselected(listBox
, text
[i
], pos
+i
+1); // Another Sergey correction
570 for (i
= 0; i
< nItems
; i
++)
571 XmStringFree(text
[i
]);
575 // It seems that if the list is cleared, we must re-ask for
576 // selection policy!!
578 XtSetArg(args
[0], XmNlistSizePolicy
, XmCONSTANT
);
579 if (m_windowStyle
& wxLB_MULTIPLE
)
580 XtSetArg(args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
581 else if (m_windowStyle
& wxLB_EXTENDED
)
582 XtSetArg(args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
583 else XtSetArg(args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
584 XtSetValues(listBox
,args
,2) ;
587 XtManageChild(listBox
);
589 GetSize(&width2
, &height2
);
590 // Correct for randomly resized listbox - bad boy, Motif!
591 if (width1
!= width2
/*|| height1 != height2*/)
592 SetSize(-1, -1, width1
, height1
);
597 void wxListBox::SetString(int N
, const wxString
& s
)
602 Widget listBox
= (Widget
) m_mainWidget
;
603 GetSize (&width1
, &height1
);
605 XmString text
= XmStringCreateSimple ((char*) (const char*) s
);
607 // delete the item and add it again.
608 // FIXME isn't there a way to change it in place?
609 XmListDeletePos (listBox
, N
+1);
610 XmListAddItem (listBox
, text
, N
+1);
614 GetSize (&width2
, &height2
);
615 // Correct for randomly resized listbox - bad boy, Motif!
616 if (width1
!= width2
|| height1
!= height2
)
617 SetSize (-1, -1, width1
, height1
);
620 int wxListBox::Number () const
625 // For single selection items only
626 wxString
wxListBox::GetStringSelection () const
629 int sel
= GetSelection();
631 res
= GetString(sel
);
636 bool wxListBox::SetStringSelection (const wxString
& s
, bool flag
)
638 int sel
= FindString (s
);
641 SetSelection (sel
, flag
);
648 void wxListBox::Command (wxCommandEvent
& event
)
650 if (event
.m_extraLong
)
651 SetSelection (event
.m_commandInt
);
654 Deselect (event
.m_commandInt
);
657 ProcessCommand (event
);
660 void wxListBoxCallback (Widget
WXUNUSED(w
), XtPointer clientData
,
661 XmListCallbackStruct
* cbs
)
664 if (cbs->reason == XmCR_EXTENDED_SELECT)
665 cout << "*** Extend select\n";
666 else if (cbs->reason == XmCR_SINGLE_SELECT)
667 cout << "*** Single select\n";
668 else if (cbs->reason == XmCR_MULTIPLE_SELECT)
669 cout << "*** Multiple select\n";
670 else if (cbs->reason == XmCR_BROWSE_SELECT)
671 cout << "*** Browse select\n";
673 if (cbs->selection_type == XmMODIFICATION)
674 cout << "*** Modification\n";
675 else if (cbs->selection_type == XmINITIAL)
676 cout << "*** Initial\n";
677 else if (cbs->selection_type == XmADDITION)
678 cout << "*** Addition\n";
681 wxListBox
*item
= (wxListBox
*) clientData
;
683 if (item
->InSetValue())
686 wxCommandEvent
event (wxEVT_COMMAND_LISTBOX_SELECTED
, item
->GetId());
689 case XmCR_MULTIPLE_SELECT
:
690 case XmCR_BROWSE_SELECT
:
692 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
693 event
.m_commandInt
= cbs
->item_position
- 1;
694 event
.m_extraLong
= TRUE
;
695 event
.SetEventObject(item
);
696 item
->ProcessCommand (event
);
699 case XmCR_EXTENDED_SELECT
:
701 switch (cbs
->selection_type
)
707 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
708 event
.m_commandInt
= cbs
->item_position
- 1;
709 event
.m_extraLong
= TRUE
;
710 event
.SetEventObject(item
);
711 item
->ProcessCommand (event
);
720 /* Respond by getting the
721 * designated "default button" in the action area and activate it
722 * as if the user had selected it.
724 void wxListBoxDefaultActionProc (Widget
WXUNUSED(list_w
), XtPointer client_data
, XmListCallbackStruct
* WXUNUSED(cbs
))
726 wxListBox
*lbox
= (wxListBox
*) client_data
;
728 wxCommandEvent
event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
, lbox
->GetId());
729 event
.SetEventObject( lbox
);
730 lbox
->GetEventHandler()->ProcessEvent(event
) ;
733 WXWidget
wxListBox::GetTopWidget() const
735 return (WXWidget
) XtParent( (Widget
) m_mainWidget
);
738 void wxListBox::ChangeFont(bool keepOriginalSize
)
740 wxWindow::ChangeFont(keepOriginalSize
);
743 void wxListBox::ChangeBackgroundColour()
745 wxWindow::ChangeBackgroundColour();
747 Widget parent
= XtParent ((Widget
) m_mainWidget
);
750 XtVaGetValues (parent
,
751 XmNhorizontalScrollBar
, &hsb
,
752 XmNverticalScrollBar
, &vsb
,
755 /* TODO: should scrollbars be affected? Should probably have separate
756 * function to change them (by default, taken from wxSystemSettings)
758 wxColour backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
);
759 DoChangeBackgroundColour((WXWidget
) hsb
, backgroundColour
, TRUE
);
760 DoChangeBackgroundColour((WXWidget
) vsb
, backgroundColour
, TRUE
);
763 XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(hsb
)),
766 XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(vsb
)),
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
,
784 /* TODO: should scrollbars be affected? Should probably have separate
785 function to change them (by default, taken from wxSystemSettings)
787 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
788 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
789 DoChangeForegroundColour((WXWidget) parent, m_foregroundColour);
793 // These implement functions needed by wxControlWithItems.
794 // Unfortunately, they're not all implemented yet.
796 int wxListBox::GetCount() const
801 int wxListBox::DoAppend(const wxString
& item
)
803 Append(item
, (void*) NULL
);
804 return GetCount() - 1;
807 // Just appends, doesn't yet insert
808 void wxListBox::DoInsertItems(const wxArrayString
& items
, int WXUNUSED(pos
))
810 size_t nItems
= items
.GetCount();
812 for ( size_t n
= 0; n
< nItems
; n
++ )
814 Append( items
[n
], (void*) NULL
);
818 void wxListBox::DoSetItems(const wxArrayString
& items
, void **clientData
)
820 size_t nItems
= items
.GetCount();
821 wxString
* strings
= new wxString
[nItems
];
823 for ( size_t n
= 0; n
< nItems
; n
++ )
825 strings
[n
] = items
[n
];
827 Set(nItems
, strings
, clientData
);
832 void wxListBox::DoSetFirstItem(int WXUNUSED(n
))
834 wxFAIL_MSG( wxT("wxListBox::DoSetFirstItem not implemented") );
837 void wxListBox::DoSetItemClientData(int n
, void* clientData
)
839 SetClientData(n
, clientData
);
842 void* wxListBox::DoGetItemClientData(int n
) const
844 return GetClientData(n
);
847 void wxListBox::DoSetItemClientObject(int n
, wxClientData
* clientData
)
849 DoSetItemClientData(n
, (void*) clientData
);
852 wxClientData
* wxListBox::DoGetItemClientObject(int n
) const
854 return (wxClientData
*) DoGetItemClientData(n
);
857 void wxListBox::Select(int n
)
859 SetSelection(n
, TRUE
);