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 #if !USE_SHARED_LIBRARY
32 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControl
)
35 static void wxListBoxCallback(Widget w
,
37 XmListCallbackStruct
* cbs
);
39 static void wxListBoxDefaultActionProc(Widget list_w
,
40 XtPointer client_data
,
41 XmListCallbackStruct
* cbs
);
43 // ============================================================================
44 // list box control implementation
45 // ============================================================================
48 wxListBox::wxListBox() : m_clientDataList(wxKEY_INTEGER
)
54 bool wxListBox::Create(wxWindow
*parent
, wxWindowID id
,
57 int n
, const wxString choices
[],
59 const wxValidator
& validator
,
62 m_windowStyle
= style
;
65 // m_backgroundColour = parent->GetBackgroundColour();
66 m_backgroundColour
= * wxWHITE
;
67 m_foregroundColour
= parent
->GetForegroundColour();
70 SetValidator(validator
);
72 if (parent
) parent
->AddChild(this);
74 m_windowId
= ( id
== -1 ) ? (int)NewControlId() : id
;
76 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
80 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
81 if (m_windowStyle
& wxLB_MULTIPLE
)
82 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
83 else if (m_windowStyle
& wxLB_EXTENDED
)
84 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
86 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
87 if (m_windowStyle
& wxLB_ALWAYS_SB
)
89 XtSetArg (args
[2], XmNscrollBarDisplayPolicy
, XmSTATIC
);
95 Widget listWidget
= XmCreateScrolledList (parentWidget
, (char*) (const char*) name
, args
, count
);
97 m_mainWidget
= (WXWidget
) listWidget
;
101 XtManageChild (listWidget
);
104 long height
= size
.y
;
110 XtAddCallback (listWidget
, XmNbrowseSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
112 XtAddCallback (listWidget
, XmNextendedSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
114 XtAddCallback (listWidget
, XmNmultipleSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
117 XtAddCallback (listWidget
, XmNdefaultActionCallback
, (XtCallbackProc
) wxListBoxDefaultActionProc
,
120 m_font
= parent
->GetFont();
123 SetCanAddEventHandler(TRUE
);
124 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, width
, height
);
126 ChangeBackgroundColour();
131 wxListBox::~wxListBox()
135 void wxListBox::SetFirstItem(int N
)
141 XtVaGetValues ((Widget
) m_mainWidget
,
142 XmNvisibleItemCount
, &count
,
143 XmNitemCount
, &length
,
145 if ((N
+ count
) >= length
)
147 XmListSetPos ((Widget
) m_mainWidget
, N
+ 1);
150 void wxListBox::SetFirstItem(const wxString
& s
)
152 int N
= FindString (s
);
158 void wxListBox::Delete(int N
)
162 Widget listBox
= (Widget
) m_mainWidget
;
163 GetSize (&width1
, &height1
);
165 bool managed
= XtIsManaged(listBox
);
168 XtUnmanageChild (listBox
);
170 XmListDeletePos (listBox
, N
+ 1);
173 XtManageChild (listBox
);
175 GetSize (&width2
, &height2
);
176 // Correct for randomly resized listbox - bad boy, Motif!
177 if (width1
!= width2
|| height1
!= height2
)
178 SetSize (-1, -1, width1
, height1
);
180 // (JDH) need to add code here to take care of clientDataList
181 wxNode
*node
= m_clientDataList
.Find((long)N
); // get item from list
182 if (node
) m_clientDataList
.DeleteNode(node
); // if existed then delete from list
183 node
= m_clientDataList
.First(); // we now have to adjust all keys that
184 while (node
) // are >=N+1
186 if (node
->GetKeyInteger() >= (long)(N
+1))
187 node
->SetKeyInteger(node
->GetKeyInteger() - 1);
194 void wxListBox::Append(const wxString
& item
)
199 Widget listBox
= (Widget
) m_mainWidget
;
200 GetSize (&width1
, &height1
);
202 bool managed
= XtIsManaged(listBox
);
205 XtUnmanageChild (listBox
);
207 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
208 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
209 // XmListAddItem(listBox, text, n + 1);
210 XmListAddItemUnselected (listBox
, text
, 0);
213 // It seems that if the list is cleared, we must re-ask for
214 // selection policy!!
216 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
217 if (m_windowStyle
& wxLB_MULTIPLE
)
218 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
219 else if (m_windowStyle
& wxLB_EXTENDED
)
220 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
222 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
223 XtSetValues (listBox
, args
, 2);
226 XtManageChild (listBox
);
228 GetSize (&width2
, &height2
);
229 // Correct for randomly resized listbox - bad boy, Motif!
230 if (width1
!= width2
|| height1
!= height2
)
231 SetSize (-1, -1, width1
, height1
);
235 void wxListBox::Append(const wxString
& item
, void *clientData
)
240 Widget listBox
= (Widget
) m_mainWidget
;
242 GetSize (&width1
, &height1
);
243 Bool managed
= XtIsManaged(listBox
);
246 XtUnmanageChild (listBox
);
249 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
250 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
251 // XmListAddItem(listBox, text, n + 1);
252 XmListAddItemUnselected (listBox
, text
, 0);
255 // It seems that if the list is cleared, we must re-ask for
256 // selection policy!!
258 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
259 if (m_windowStyle
& wxLB_MULTIPLE
)
260 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
261 else if (m_windowStyle
& wxLB_EXTENDED
)
262 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
264 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
265 XtSetValues (listBox
, args
, 2);
267 m_clientDataList
.Append ((long) n
, (wxObject
*) clientData
);
270 XtManageChild (listBox
);
272 GetSize (&width2
, &height2
);
274 // Correct for randomly resized listbox - bad boy, Motif!
275 if (width1
!= width2
|| height1
!= height2
)
276 SetSize (-1, -1, width1
, height1
);
281 void wxListBox::Set(int n
, const wxString
*choices
, void** clientData
)
283 m_clientDataList
.Clear();
287 Widget listBox
= (Widget
) m_mainWidget
;
288 GetSize (&width1
, &height1
);
290 bool managed
= XtIsManaged(listBox
);
293 XtUnmanageChild (listBox
);
295 for (int i=0; i<n; i++)
297 XmString text = XmStringCreateSimple(choices[i]);
298 XmListAddItemUnselected(listBox, text, 0);
302 XmString
*text
= new XmString
[n
];
304 for (i
= 0; i
< n
; i
++)
305 text
[i
] = XmStringCreateSimple ((char*) (const char*) choices
[i
]);
308 for (i
= 0; i
< n
; i
++)
309 m_clientDataList
.Append ((long) i
, (wxObject
*) clientData
[i
]);
311 XmListAddItems (listBox
, text
, n
, 0);
312 for (i
= 0; i
< n
; i
++)
313 XmStringFree (text
[i
]);
316 // It seems that if the list is cleared, we must re-ask for
317 // selection policy!!
319 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
320 if (m_windowStyle
& wxLB_MULTIPLE
)
321 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
322 else if (m_windowStyle
& wxLB_EXTENDED
)
323 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
325 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
326 XtSetValues (listBox
, args
, 2);
329 XtManageChild (listBox
);
331 GetSize (&width2
, &height2
);
332 // Correct for randomly resized listbox - bad boy, Motif!
333 if (width1
!= width2
|| height1
!= height2
)
334 SetSize (-1, -1, width1
, height1
);
339 int wxListBox::FindString(const wxString
& s
) const
341 XmString str
= XmStringCreateSimple ((char*) (const char*) s
);
342 int *positions
= NULL
;
343 int no_positions
= 0;
344 bool success
= XmListGetMatchPos ((Widget
) m_mainWidget
, str
, &positions
, &no_positions
);
348 int pos
= positions
[0];
350 XtFree ((char *) positions
);
357 void wxListBox::Clear()
365 Widget listBox
= (Widget
) m_mainWidget
;
366 GetSize (&width1
, &height1
);
368 XmListDeleteAllItems (listBox
);
369 m_clientDataList
.Clear ();
370 GetSize (&width2
, &height2
);
372 // Correct for randomly resized listbox - bad boy, Motif!
373 if (width1
!= width2
|| height1
!= height2
)
374 SetSize (-1, -1, width1
, height1
);
379 void wxListBox::SetSelection(int N
, bool select
)
385 if (m_windowStyle
& wxLB_MULTIPLE
)
387 int *selections
= NULL
;
388 int n
= GetSelections (&selections
);
390 // This hack is supposed to work, to make it possible to select more
391 // than one item, but it DOESN'T under Motif 1.1.
393 XtVaSetValues ((Widget
) m_mainWidget
, XmNselectionPolicy
, XmMULTIPLE_SELECT
, NULL
);
396 for (i
= 0; i
< n
; i
++)
397 XmListSelectPos ((Widget
) m_mainWidget
, selections
[i
] + 1, FALSE
);
399 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
401 XtVaSetValues ((Widget
) m_mainWidget
, XmNselectionPolicy
, XmEXTENDED_SELECT
, NULL
);
405 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
409 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
411 m_inSetValue
= FALSE
;
414 bool wxListBox::Selected(int N
) const
416 // In Motif, no simple way to determine if the item is selected.
417 wxArrayInt theSelections
;
418 int count
= GetSelections (theSelections
);
424 for (j
= 0; j
< count
; j
++)
425 if (theSelections
[j
] == N
)
431 void wxListBox::Deselect(int N
)
433 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
436 void *wxListBox::GetClientData(int N
) const
438 wxNode
*node
= m_clientDataList
.Find ((long) N
);
440 return (void *) node
->Data ();
445 void wxListBox::SetClientData(int N
, void *Client_data
)
447 wxNode
*node
= m_clientDataList
.Find ((long) N
);
449 node
->SetData ((wxObject
*)Client_data
);
451 node
= m_clientDataList
.Append((long) N
, (wxObject
*) Client_data
);
454 // Return number of selections and an array of selected integers
455 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const
459 Widget listBox
= (Widget
) m_mainWidget
;
462 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
467 aSelections
.Alloc(posCnt
);
470 for (i
= 0; i
< posCnt
; i
++)
471 aSelections
.Add(posList
[i
] - 1);
473 XtFree ((char *) posList
);
483 // Get single selection, for single choice list items
484 int wxListBox::GetSelection() const
486 Widget listBox
= (Widget
) m_mainWidget
;
489 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
495 XtFree ((char *) posList
);
502 // Find string for position
503 wxString
wxListBox::GetString(int N
) const
505 Widget listBox
= (Widget
) m_mainWidget
;
508 XtVaGetValues (listBox
, XmNitemCount
, &n
, XmNitems
, &strlist
, NULL
);
509 if (N
<= n
&& N
>= 0)
512 if (XmStringGetLtoR (strlist
[N
], XmSTRING_DEFAULT_CHARSET
, &txt
))
519 return wxEmptyString
;
522 return wxEmptyString
;
525 void wxListBox::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
527 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
529 // Check resulting size is correct
531 GetSize (&tempW
, &tempH
);
534 if (tempW != width || tempH != height)
536 cout << "wxListBox::SetSize sizes not set correctly.");
541 void wxListBox::InsertItems(int nItems
, const wxString items
[], int pos
)
546 Widget listBox
= (Widget
) m_mainWidget
;
548 GetSize(&width1
, &height1
);
550 bool managed
= XtIsManaged(listBox
);
553 XtUnmanageChild(listBox
);
555 XmString
*text
= new XmString
[nItems
];
557 // Steve Hammes: Motif 1.1 compatibility
558 // #if XmVersion > 1100
559 // Corrected by Sergey Krasnov from Steve Hammes' code
561 for (i
= 0; i
< nItems
; i
++)
562 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
563 XmListAddItemsUnselected(listBox
, text
, nItems
, pos
+1);
565 for (i
= 0; i
< nItems
; i
++)
567 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
568 // XmListAddItemUnselected(listBox, text[i], i);
569 XmListAddItemUnselected(listBox
, text
[i
], pos
+i
+1); // Another Sergey correction
572 for (i
= 0; i
< nItems
; i
++)
573 XmStringFree(text
[i
]);
577 // It seems that if the list is cleared, we must re-ask for
578 // selection policy!!
580 XtSetArg(args
[0], XmNlistSizePolicy
, XmCONSTANT
);
581 if (m_windowStyle
& wxLB_MULTIPLE
)
582 XtSetArg(args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
583 else if (m_windowStyle
& wxLB_EXTENDED
)
584 XtSetArg(args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
585 else XtSetArg(args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
586 XtSetValues(listBox
,args
,2) ;
589 XtManageChild(listBox
);
591 GetSize(&width2
, &height2
);
592 // Correct for randomly resized listbox - bad boy, Motif!
593 if (width1
!= width2
/*|| height1 != height2*/)
594 SetSize(-1, -1, width1
, height1
);
599 void wxListBox::SetString(int N
, const wxString
& s
)
604 Widget listBox
= (Widget
) m_mainWidget
;
605 GetSize (&width1
, &height1
);
607 XmString text
= XmStringCreateSimple ((char*) (const char*) s
);
609 // delete the item and add it again.
610 // FIXME isn't there a way to change it in place?
611 XmListDeletePos (listBox
, N
+1);
612 XmListAddItem (listBox
, text
, N
+1);
616 GetSize (&width2
, &height2
);
617 // Correct for randomly resized listbox - bad boy, Motif!
618 if (width1
!= width2
|| height1
!= height2
)
619 SetSize (-1, -1, width1
, height1
);
622 int wxListBox::Number () const
627 // For single selection items only
628 wxString
wxListBox::GetStringSelection () const
631 int sel
= GetSelection();
633 res
= GetString(sel
);
638 bool wxListBox::SetStringSelection (const wxString
& s
, bool flag
)
640 int sel
= FindString (s
);
643 SetSelection (sel
, flag
);
650 void wxListBox::Command (wxCommandEvent
& event
)
652 if (event
.m_extraLong
)
653 SetSelection (event
.m_commandInt
);
656 Deselect (event
.m_commandInt
);
659 ProcessCommand (event
);
662 void wxListBoxCallback (Widget
WXUNUSED(w
), XtPointer clientData
,
663 XmListCallbackStruct
* cbs
)
666 if (cbs->reason == XmCR_EXTENDED_SELECT)
667 cout << "*** Extend select\n";
668 else if (cbs->reason == XmCR_SINGLE_SELECT)
669 cout << "*** Single select\n";
670 else if (cbs->reason == XmCR_MULTIPLE_SELECT)
671 cout << "*** Multiple select\n";
672 else if (cbs->reason == XmCR_BROWSE_SELECT)
673 cout << "*** Browse select\n";
675 if (cbs->selection_type == XmMODIFICATION)
676 cout << "*** Modification\n";
677 else if (cbs->selection_type == XmINITIAL)
678 cout << "*** Initial\n";
679 else if (cbs->selection_type == XmADDITION)
680 cout << "*** Addition\n";
683 wxListBox
*item
= (wxListBox
*) clientData
;
685 if (item
->InSetValue())
688 wxCommandEvent
event (wxEVT_COMMAND_LISTBOX_SELECTED
, item
->GetId());
691 case XmCR_MULTIPLE_SELECT
:
692 case XmCR_BROWSE_SELECT
:
694 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
695 event
.m_commandInt
= cbs
->item_position
- 1;
696 event
.m_extraLong
= TRUE
;
697 event
.SetEventObject(item
);
698 item
->ProcessCommand (event
);
701 case XmCR_EXTENDED_SELECT
:
703 switch (cbs
->selection_type
)
709 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
710 event
.m_commandInt
= cbs
->item_position
- 1;
711 event
.m_extraLong
= TRUE
;
712 event
.SetEventObject(item
);
713 item
->ProcessCommand (event
);
722 /* Respond by getting the
723 * designated "default button" in the action area and activate it
724 * as if the user had selected it.
726 void wxListBoxDefaultActionProc (Widget
WXUNUSED(list_w
), XtPointer client_data
, XmListCallbackStruct
* WXUNUSED(cbs
))
728 wxListBox
*lbox
= (wxListBox
*) client_data
;
730 wxCommandEvent
event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
, lbox
->GetId());
731 event
.SetEventObject( lbox
);
732 lbox
->GetEventHandler()->ProcessEvent(event
) ;
735 WXWidget
wxListBox::GetTopWidget() const
737 return (WXWidget
) XtParent( (Widget
) m_mainWidget
);
740 void wxListBox::ChangeFont(bool keepOriginalSize
)
742 wxWindow::ChangeFont(keepOriginalSize
);
745 void wxListBox::ChangeBackgroundColour()
747 wxWindow::ChangeBackgroundColour();
749 Widget parent
= XtParent ((Widget
) m_mainWidget
);
752 XtVaGetValues (parent
,
753 XmNhorizontalScrollBar
, &hsb
,
754 XmNverticalScrollBar
, &vsb
,
757 /* TODO: should scrollbars be affected? Should probably have separate
758 * function to change them (by default, taken from wxSystemSettings)
760 wxColour backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
);
761 DoChangeBackgroundColour((WXWidget
) hsb
, backgroundColour
, TRUE
);
762 DoChangeBackgroundColour((WXWidget
) vsb
, backgroundColour
, TRUE
);
765 XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(hsb
)),
768 XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(vsb
)),
771 DoChangeBackgroundColour((WXWidget
) parent
, m_backgroundColour
, TRUE
);
774 void wxListBox::ChangeForegroundColour()
776 wxWindow::ChangeForegroundColour();
778 Widget parent
= XtParent ((Widget
) m_mainWidget
);
781 XtVaGetValues(parent
,
782 XmNhorizontalScrollBar
, &hsb
,
783 XmNverticalScrollBar
, &vsb
,
786 /* TODO: should scrollbars be affected? Should probably have separate
787 function to change them (by default, taken from wxSystemSettings)
789 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
790 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
791 DoChangeForegroundColour((WXWidget) parent, m_foregroundColour);
795 // These implement functions needed by wxControlWithItems.
796 // Unfortunately, they're not all implemented yet.
798 int wxListBox::GetCount() const
803 int wxListBox::DoAppend(const wxString
& item
)
805 Append(item
, (void*) NULL
);
806 return GetCount() - 1;
809 // Just appends, doesn't yet insert
810 void wxListBox::DoInsertItems(const wxArrayString
& items
, int WXUNUSED(pos
))
812 size_t nItems
= items
.GetCount();
814 for ( size_t n
= 0; n
< nItems
; n
++ )
816 Append( items
[n
], (void*) NULL
);
820 void wxListBox::DoSetItems(const wxArrayString
& items
, void **clientData
)
822 size_t nItems
= items
.GetCount();
823 wxString
* strings
= new wxString
[nItems
];
825 for ( size_t n
= 0; n
< nItems
; n
++ )
827 strings
[n
] = items
[n
];
829 Set(nItems
, strings
, clientData
);
834 void wxListBox::DoSetFirstItem(int WXUNUSED(n
))
836 wxFAIL_MSG( wxT("wxListBox::DoSetFirstItem not implemented") );
839 void wxListBox::DoSetItemClientData(int n
, void* clientData
)
841 SetClientData(n
, clientData
);
844 void* wxListBox::DoGetItemClientData(int n
) const
846 return GetClientData(n
);
849 void wxListBox::DoSetItemClientObject(int n
, wxClientData
* clientData
)
851 DoSetItemClientData(n
, (void*) clientData
);
854 wxClientData
* wxListBox::DoGetItemClientObject(int n
) const
856 return (wxClientData
*) DoGetItemClientData(n
);
859 void wxListBox::Select(int n
)
861 SetSelection(n
, TRUE
);