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 static void wxListBoxDefaultActionProc(Widget list_w
,
43 XtPointer client_data
,
44 XmListCallbackStruct
* cbs
);
46 // ============================================================================
47 // list box control implementation
48 // ============================================================================
51 wxListBox::wxListBox() : m_clientDataList(wxKEY_INTEGER
)
57 bool wxListBox::Create(wxWindow
*parent
, wxWindowID id
,
60 int n
, const wxString choices
[],
62 const wxValidator
& validator
,
65 m_windowStyle
= style
;
68 // m_backgroundColour = parent->GetBackgroundColour();
69 m_backgroundColour
= * wxWHITE
;
70 m_foregroundColour
= parent
->GetForegroundColour();
73 SetValidator(validator
);
75 if (parent
) parent
->AddChild(this);
77 m_windowId
= ( id
== -1 ) ? (int)NewControlId() : id
;
79 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
83 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
84 if (m_windowStyle
& wxLB_MULTIPLE
)
85 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
86 else if (m_windowStyle
& wxLB_EXTENDED
)
87 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
89 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
90 if (m_windowStyle
& wxLB_ALWAYS_SB
)
92 XtSetArg (args
[2], XmNscrollBarDisplayPolicy
, XmSTATIC
);
98 Widget listWidget
= XmCreateScrolledList (parentWidget
, (char*) (const char*) name
, args
, count
);
100 m_mainWidget
= (WXWidget
) listWidget
;
104 XtManageChild (listWidget
);
107 long height
= size
.y
;
113 XtAddCallback (listWidget
, XmNbrowseSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
115 XtAddCallback (listWidget
, XmNextendedSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
117 XtAddCallback (listWidget
, XmNmultipleSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
120 XtAddCallback (listWidget
, XmNdefaultActionCallback
, (XtCallbackProc
) wxListBoxDefaultActionProc
,
123 m_font
= parent
->GetFont();
126 SetCanAddEventHandler(TRUE
);
127 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, width
, height
);
129 ChangeBackgroundColour();
134 wxListBox::~wxListBox()
138 void wxListBox::SetFirstItem(int N
)
144 XtVaGetValues ((Widget
) m_mainWidget
,
145 XmNvisibleItemCount
, &count
,
146 XmNitemCount
, &length
,
148 if ((N
+ count
) >= length
)
150 XmListSetPos ((Widget
) m_mainWidget
, N
+ 1);
153 void wxListBox::SetFirstItem(const wxString
& s
)
155 int N
= FindString (s
);
161 void wxListBox::Delete(int N
)
165 Widget listBox
= (Widget
) m_mainWidget
;
166 GetSize (&width1
, &height1
);
168 bool managed
= XtIsManaged(listBox
);
171 XtUnmanageChild (listBox
);
173 XmListDeletePos (listBox
, N
+ 1);
176 XtManageChild (listBox
);
178 GetSize (&width2
, &height2
);
179 // Correct for randomly resized listbox - bad boy, Motif!
180 if (width1
!= width2
|| height1
!= height2
)
181 SetSize (-1, -1, width1
, height1
);
183 // (JDH) need to add code here to take care of clientDataList
184 wxNode
*node
= m_clientDataList
.Find((long)N
); // get item from list
185 if (node
) m_clientDataList
.DeleteNode(node
); // if existed then delete from list
186 node
= m_clientDataList
.First(); // we now have to adjust all keys that
187 while (node
) // are >=N+1
189 if (node
->GetKeyInteger() >= (long)(N
+1))
190 node
->SetKeyInteger(node
->GetKeyInteger() - 1);
197 void wxListBox::Append(const wxString
& item
)
202 Widget listBox
= (Widget
) m_mainWidget
;
203 GetSize (&width1
, &height1
);
205 bool managed
= XtIsManaged(listBox
);
208 XtUnmanageChild (listBox
);
210 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
211 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
212 // XmListAddItem(listBox, text, n + 1);
213 XmListAddItemUnselected (listBox
, text
, 0);
216 // It seems that if the list is cleared, we must re-ask for
217 // selection policy!!
219 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
220 if (m_windowStyle
& wxLB_MULTIPLE
)
221 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
222 else if (m_windowStyle
& wxLB_EXTENDED
)
223 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
225 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
226 XtSetValues (listBox
, args
, 2);
229 XtManageChild (listBox
);
231 GetSize (&width2
, &height2
);
232 // Correct for randomly resized listbox - bad boy, Motif!
233 if (width1
!= width2
|| height1
!= height2
)
234 SetSize (-1, -1, width1
, height1
);
238 void wxListBox::Append(const wxString
& item
, void *clientData
)
243 Widget listBox
= (Widget
) m_mainWidget
;
245 GetSize (&width1
, &height1
);
246 Bool managed
= XtIsManaged(listBox
);
249 XtUnmanageChild (listBox
);
252 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
253 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
254 // XmListAddItem(listBox, text, n + 1);
255 XmListAddItemUnselected (listBox
, text
, 0);
258 // It seems that if the list is cleared, we must re-ask for
259 // selection policy!!
261 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
262 if (m_windowStyle
& wxLB_MULTIPLE
)
263 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
264 else if (m_windowStyle
& wxLB_EXTENDED
)
265 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
267 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
268 XtSetValues (listBox
, args
, 2);
270 m_clientDataList
.Append ((long) n
, (wxObject
*) clientData
);
273 XtManageChild (listBox
);
275 GetSize (&width2
, &height2
);
277 // Correct for randomly resized listbox - bad boy, Motif!
278 if (width1
!= width2
|| height1
!= height2
)
279 SetSize (-1, -1, width1
, height1
);
284 void wxListBox::Set(int n
, const wxString
*choices
, void** clientData
)
286 m_clientDataList
.Clear();
290 Widget listBox
= (Widget
) m_mainWidget
;
291 GetSize (&width1
, &height1
);
293 bool managed
= XtIsManaged(listBox
);
296 XtUnmanageChild (listBox
);
298 for (int i=0; i<n; i++)
300 XmString text = XmStringCreateSimple(choices[i]);
301 XmListAddItemUnselected(listBox, text, 0);
305 XmString
*text
= new XmString
[n
];
307 for (i
= 0; i
< n
; i
++)
308 text
[i
] = XmStringCreateSimple ((char*) (const char*) choices
[i
]);
311 for (i
= 0; i
< n
; i
++)
312 m_clientDataList
.Append ((long) i
, (wxObject
*) clientData
[i
]);
314 XmListAddItems (listBox
, text
, n
, 0);
315 for (i
= 0; i
< n
; i
++)
316 XmStringFree (text
[i
]);
319 // It seems that if the list is cleared, we must re-ask for
320 // selection policy!!
322 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
323 if (m_windowStyle
& wxLB_MULTIPLE
)
324 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
325 else if (m_windowStyle
& wxLB_EXTENDED
)
326 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
328 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
329 XtSetValues (listBox
, args
, 2);
332 XtManageChild (listBox
);
334 GetSize (&width2
, &height2
);
335 // Correct for randomly resized listbox - bad boy, Motif!
336 if (width1
!= width2
|| height1
!= height2
)
337 SetSize (-1, -1, width1
, height1
);
342 int wxListBox::FindString(const wxString
& s
) const
344 XmString str
= XmStringCreateSimple ((char*) (const char*) s
);
345 int *positions
= NULL
;
346 int no_positions
= 0;
347 bool success
= XmListGetMatchPos ((Widget
) m_mainWidget
, str
, &positions
, &no_positions
);
351 int pos
= positions
[0];
353 XtFree ((char *) positions
);
360 void wxListBox::Clear()
368 Widget listBox
= (Widget
) m_mainWidget
;
369 GetSize (&width1
, &height1
);
371 XmListDeleteAllItems (listBox
);
372 m_clientDataList
.Clear ();
373 GetSize (&width2
, &height2
);
375 // Correct for randomly resized listbox - bad boy, Motif!
376 if (width1
!= width2
|| height1
!= height2
)
377 SetSize (-1, -1, width1
, height1
);
382 void wxListBox::SetSelection(int N
, bool select
)
388 if (m_windowStyle
& wxLB_MULTIPLE
)
390 int *selections
= NULL
;
391 int n
= GetSelections (&selections
);
393 // This hack is supposed to work, to make it possible to select more
394 // than one item, but it DOESN'T under Motif 1.1.
396 XtVaSetValues ((Widget
) m_mainWidget
, XmNselectionPolicy
, XmMULTIPLE_SELECT
, NULL
);
399 for (i
= 0; i
< n
; i
++)
400 XmListSelectPos ((Widget
) m_mainWidget
, selections
[i
] + 1, FALSE
);
402 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
404 XtVaSetValues ((Widget
) m_mainWidget
, XmNselectionPolicy
, XmEXTENDED_SELECT
, NULL
);
408 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
412 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
414 m_inSetValue
= FALSE
;
417 bool wxListBox::IsSelected(int N
) const
419 // In Motif, no simple way to determine if the item is selected.
420 wxArrayInt theSelections
;
421 int count
= GetSelections (theSelections
);
427 for (j
= 0; j
< count
; j
++)
428 if (theSelections
[j
] == N
)
434 void wxListBox::Deselect(int N
)
436 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
439 void *wxListBox::GetClientData(int N
) const
441 wxNode
*node
= m_clientDataList
.Find ((long) N
);
443 return (void *) node
->Data ();
448 void wxListBox::SetClientData(int N
, void *Client_data
)
450 wxNode
*node
= m_clientDataList
.Find ((long) N
);
452 node
->SetData ((wxObject
*)Client_data
);
454 node
= m_clientDataList
.Append((long) N
, (wxObject
*) Client_data
);
457 // Return number of selections and an array of selected integers
458 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const
462 Widget listBox
= (Widget
) m_mainWidget
;
465 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
470 aSelections
.Alloc(posCnt
);
473 for (i
= 0; i
< posCnt
; i
++)
474 aSelections
.Add(posList
[i
] - 1);
476 XtFree ((char *) posList
);
486 // Get single selection, for single choice list items
487 int wxListBox::GetSelection() const
489 Widget listBox
= (Widget
) m_mainWidget
;
492 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
498 XtFree ((char *) posList
);
505 // Find string for position
506 wxString
wxListBox::GetString(int N
) const
508 Widget listBox
= (Widget
) m_mainWidget
;
511 XtVaGetValues (listBox
, XmNitemCount
, &n
, XmNitems
, &strlist
, NULL
);
512 if (N
<= n
&& N
>= 0)
515 if (XmStringGetLtoR (strlist
[N
], XmSTRING_DEFAULT_CHARSET
, &txt
))
522 return wxEmptyString
;
525 return wxEmptyString
;
528 void wxListBox::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
530 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
532 // Check resulting size is correct
534 GetSize (&tempW
, &tempH
);
537 if (tempW != width || tempH != height)
539 cout << "wxListBox::SetSize sizes not set correctly.");
544 void wxListBox::InsertItems(int nItems
, const wxString items
[], int pos
)
549 Widget listBox
= (Widget
) m_mainWidget
;
551 GetSize(&width1
, &height1
);
553 bool managed
= XtIsManaged(listBox
);
556 XtUnmanageChild(listBox
);
558 XmString
*text
= new XmString
[nItems
];
560 // Steve Hammes: Motif 1.1 compatibility
561 // #if XmVersion > 1100
562 // Corrected by Sergey Krasnov from Steve Hammes' code
564 for (i
= 0; i
< nItems
; i
++)
565 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
566 XmListAddItemsUnselected(listBox
, text
, nItems
, pos
+1);
568 for (i
= 0; i
< nItems
; i
++)
570 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
571 // XmListAddItemUnselected(listBox, text[i], i);
572 XmListAddItemUnselected(listBox
, text
[i
], pos
+i
+1); // Another Sergey correction
575 for (i
= 0; i
< nItems
; i
++)
576 XmStringFree(text
[i
]);
580 // It seems that if the list is cleared, we must re-ask for
581 // selection policy!!
583 XtSetArg(args
[0], XmNlistSizePolicy
, XmCONSTANT
);
584 if (m_windowStyle
& wxLB_MULTIPLE
)
585 XtSetArg(args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
586 else if (m_windowStyle
& wxLB_EXTENDED
)
587 XtSetArg(args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
588 else XtSetArg(args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
589 XtSetValues(listBox
,args
,2) ;
592 XtManageChild(listBox
);
594 GetSize(&width2
, &height2
);
595 // Correct for randomly resized listbox - bad boy, Motif!
596 if (width1
!= width2
/*|| height1 != height2*/)
597 SetSize(-1, -1, width1
, height1
);
602 void wxListBox::SetString(int N
, const wxString
& s
)
607 Widget listBox
= (Widget
) m_mainWidget
;
608 GetSize (&width1
, &height1
);
610 XmString text
= XmStringCreateSimple ((char*) (const char*) s
);
612 // delete the item and add it again.
613 // FIXME isn't there a way to change it in place?
614 XmListDeletePos (listBox
, N
+1);
615 XmListAddItem (listBox
, text
, N
+1);
619 GetSize (&width2
, &height2
);
620 // Correct for randomly resized listbox - bad boy, Motif!
621 if (width1
!= width2
|| height1
!= height2
)
622 SetSize (-1, -1, width1
, height1
);
625 int wxListBox::Number () const
630 // For single selection items only
631 wxString
wxListBox::GetStringSelection () const
634 int sel
= GetSelection();
636 res
= 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
WXUNUSED(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
.m_commandInt
= cbs
->item_position
- 1;
699 event
.m_extraLong
= TRUE
;
700 event
.SetEventObject(item
);
701 item
->ProcessCommand (event
);
704 case XmCR_EXTENDED_SELECT
:
706 switch (cbs
->selection_type
)
712 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
713 event
.m_commandInt
= cbs
->item_position
- 1;
714 event
.m_extraLong
= TRUE
;
715 event
.SetEventObject(item
);
716 item
->ProcessCommand (event
);
725 /* Respond by getting the
726 * designated "default button" in the action area and activate it
727 * as if the user had selected it.
729 void wxListBoxDefaultActionProc (Widget
WXUNUSED(list_w
), XtPointer client_data
, XmListCallbackStruct
* WXUNUSED(cbs
))
731 wxListBox
*lbox
= (wxListBox
*) client_data
;
733 wxCommandEvent
event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
, lbox
->GetId());
734 event
.SetEventObject( lbox
);
735 lbox
->GetEventHandler()->ProcessEvent(event
) ;
738 WXWidget
wxListBox::GetTopWidget() const
740 return (WXWidget
) XtParent( (Widget
) m_mainWidget
);
743 void wxListBox::ChangeFont(bool keepOriginalSize
)
745 wxWindow::ChangeFont(keepOriginalSize
);
748 void wxListBox::ChangeBackgroundColour()
750 wxWindow::ChangeBackgroundColour();
752 Widget parent
= XtParent ((Widget
) m_mainWidget
);
755 XtVaGetValues (parent
,
756 XmNhorizontalScrollBar
, &hsb
,
757 XmNverticalScrollBar
, &vsb
,
760 /* TODO: should scrollbars be affected? Should probably have separate
761 * function to change them (by default, taken from wxSystemSettings)
763 wxColour backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
764 DoChangeBackgroundColour((WXWidget
) hsb
, backgroundColour
, TRUE
);
765 DoChangeBackgroundColour((WXWidget
) vsb
, backgroundColour
, TRUE
);
768 XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(hsb
)),
771 XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(vsb
)),
774 DoChangeBackgroundColour((WXWidget
) parent
, m_backgroundColour
, TRUE
);
777 void wxListBox::ChangeForegroundColour()
779 wxWindow::ChangeForegroundColour();
781 Widget parent
= XtParent ((Widget
) m_mainWidget
);
784 XtVaGetValues(parent
,
785 XmNhorizontalScrollBar
, &hsb
,
786 XmNverticalScrollBar
, &vsb
,
789 /* TODO: should scrollbars be affected? Should probably have separate
790 function to change them (by default, taken from wxSystemSettings)
792 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
793 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
794 DoChangeForegroundColour((WXWidget) parent, m_foregroundColour);
798 // These implement functions needed by wxControlWithItems.
799 // Unfortunately, they're not all implemented yet.
801 int wxListBox::GetCount() const
806 int wxListBox::DoAppend(const wxString
& item
)
808 Append(item
, (void*) NULL
);
809 return GetCount() - 1;
812 // Just appends, doesn't yet insert
813 void wxListBox::DoInsertItems(const wxArrayString
& items
, int WXUNUSED(pos
))
815 size_t nItems
= items
.GetCount();
817 for ( size_t n
= 0; n
< nItems
; n
++ )
819 Append( items
[n
], (void*) NULL
);
823 void wxListBox::DoSetItems(const wxArrayString
& items
, void **clientData
)
825 size_t nItems
= items
.GetCount();
826 wxString
* strings
= new wxString
[nItems
];
828 for ( size_t n
= 0; n
< nItems
; n
++ )
830 strings
[n
] = items
[n
];
832 Set(nItems
, strings
, clientData
);
837 void wxListBox::DoSetFirstItem(int WXUNUSED(n
))
839 wxFAIL_MSG( wxT("wxListBox::DoSetFirstItem not implemented") );
842 void wxListBox::DoSetItemClientData(int n
, void* clientData
)
844 SetClientData(n
, clientData
);
847 void* wxListBox::DoGetItemClientData(int n
) const
849 return GetClientData(n
);
852 void wxListBox::DoSetItemClientObject(int n
, wxClientData
* clientData
)
854 DoSetItemClientData(n
, (void*) clientData
);
857 wxClientData
* wxListBox::DoGetItemClientObject(int n
) const
859 return (wxClientData
*) DoGetItemClientData(n
);
862 void wxListBox::Select(int n
)
864 SetSelection(n
, TRUE
);