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 SetCanAddEventHandler(TRUE
);
115 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, width
, height
);
117 ChangeBackgroundColour();
122 wxListBox::~wxListBox()
126 void wxListBox::SetFirstItem(int N
)
132 XtVaGetValues ((Widget
) m_mainWidget
,
133 XmNvisibleItemCount
, &count
,
134 XmNitemCount
, &length
,
136 if ((N
+ count
) >= length
)
138 XmListSetPos ((Widget
) m_mainWidget
, N
+ 1);
141 void wxListBox::SetFirstItem(const wxString
& s
)
143 int N
= FindString (s
);
149 void wxListBox::Delete(int N
)
153 Widget listBox
= (Widget
) m_mainWidget
;
154 GetSize (&width1
, &height1
);
156 bool managed
= XtIsManaged(listBox
);
159 XtUnmanageChild (listBox
);
161 XmListDeletePos (listBox
, N
+ 1);
164 XtManageChild (listBox
);
166 GetSize (&width2
, &height2
);
167 // Correct for randomly resized listbox - bad boy, Motif!
168 if (width1
!= width2
|| height1
!= height2
)
169 SetSize (-1, -1, width1
, height1
);
171 // (JDH) need to add code here to take care of clientDataList
172 wxNode
*node
= m_clientDataList
.Find((long)N
); // get item from list
173 if (node
) m_clientDataList
.DeleteNode(node
); // if existed then delete from list
174 node
= m_clientDataList
.First(); // we now have to adjust all keys that
175 while (node
) // are >=N+1
176 { if (node
->GetKeyInteger() >= (long)(N
+1))
177 node
->SetKeyInteger(node
->GetKeyInteger() - 1);
184 void wxListBox::Append(const wxString
& item
)
189 Widget listBox
= (Widget
) m_mainWidget
;
190 GetSize (&width1
, &height1
);
192 bool managed
= XtIsManaged(listBox
);
195 XtUnmanageChild (listBox
);
197 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
198 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
199 // XmListAddItem(listBox, text, n + 1);
200 XmListAddItemUnselected (listBox
, text
, 0);
203 // It seems that if the list is cleared, we must re-ask for
204 // selection policy!!
206 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
207 if (m_windowStyle
& wxLB_MULTIPLE
)
208 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
209 else if (m_windowStyle
& wxLB_EXTENDED
)
210 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
212 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
213 XtSetValues (listBox
, args
, 2);
216 XtManageChild (listBox
);
218 GetSize (&width2
, &height2
);
219 // Correct for randomly resized listbox - bad boy, Motif!
220 if (width1
!= width2
|| height1
!= height2
)
221 SetSize (-1, -1, width1
, height1
);
225 void wxListBox::Append(const wxString
& item
, char *clientData
)
230 Widget listBox
= (Widget
) m_mainWidget
;
232 GetSize (&width1
, &height1
);
233 Bool managed
= XtIsManaged(listBox
);
236 XtUnmanageChild (listBox
);
239 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
240 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
241 // XmListAddItem(listBox, text, n + 1);
242 XmListAddItemUnselected (listBox
, text
, 0);
245 // It seems that if the list is cleared, we must re-ask for
246 // selection policy!!
248 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
249 if (m_windowStyle
& wxLB_MULTIPLE
)
250 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
251 else if (m_windowStyle
& wxLB_EXTENDED
)
252 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
254 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
255 XtSetValues (listBox
, args
, 2);
257 m_clientDataList
.Append ((long) n
, (wxObject
*) clientData
);
260 XtManageChild (listBox
);
262 GetSize (&width2
, &height2
);
264 // Correct for randomly resized listbox - bad boy, Motif!
265 if (width1
!= width2
|| height1
!= height2
)
266 SetSize (-1, -1, width1
, height1
);
271 void wxListBox::Set(int n
, const wxString
*choices
, char** clientData
)
273 m_clientDataList
.Clear();
277 Widget listBox
= (Widget
) m_mainWidget
;
278 GetSize (&width1
, &height1
);
280 bool managed
= XtIsManaged(listBox
);
283 XtUnmanageChild (listBox
);
285 for (int i=0; i<n; i++)
287 XmString text = XmStringCreateSimple(choices[i]);
288 XmListAddItemUnselected(listBox, text, 0);
292 XmString
*text
= new XmString
[n
];
294 for (i
= 0; i
< n
; i
++)
295 text
[i
] = XmStringCreateSimple ((char*) (const char*) choices
[i
]);
298 for (i
= 0; i
< n
; i
++)
299 m_clientDataList
.Append ((long) i
, (wxObject
*) clientData
[i
]);
301 XmListAddItems (listBox
, text
, n
, 0);
302 for (i
= 0; i
< n
; i
++)
303 XmStringFree (text
[i
]);
306 // It seems that if the list is cleared, we must re-ask for
307 // selection policy!!
309 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
310 if (m_windowStyle
& wxLB_MULTIPLE
)
311 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
312 else if (m_windowStyle
& wxLB_EXTENDED
)
313 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
315 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
316 XtSetValues (listBox
, args
, 2);
319 XtManageChild (listBox
);
321 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 int wxListBox::FindString(const wxString
& s
) const
331 XmString str
= XmStringCreateSimple ((char*) (const char*) s
);
332 int *positions
= NULL
;
333 int no_positions
= 0;
334 bool success
= XmListGetMatchPos ((Widget
) m_mainWidget
, str
, &positions
, &no_positions
);
338 int pos
= positions
[0];
340 XtFree ((char *) positions
);
347 void wxListBox::Clear()
355 Widget listBox
= (Widget
) m_mainWidget
;
356 GetSize (&width1
, &height1
);
358 XmListDeleteAllItems (listBox
);
359 m_clientDataList
.Clear ();
360 GetSize (&width2
, &height2
);
362 // Correct for randomly resized listbox - bad boy, Motif!
363 if (width1
!= width2
|| height1
!= height2
)
364 SetSize (-1, -1, width1
, height1
);
369 void wxListBox::SetSelection(int N
, bool select
)
375 if (m_windowStyle & wxLB_MULTIPLE)
377 int *selections = NULL;
378 int n = GetSelections (&selections);
380 // This hack is supposed to work, to make it possible to select more
381 // than one item, but it DOESN'T under Motif 1.1.
383 XtVaSetValues ((Widget) m_mainWidget, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
386 for (i = 0; i < n; i++)
387 XmListSelectPos ((Widget) m_mainWidget, selections[i] + 1, FALSE);
389 XmListSelectPos ((Widget) m_mainWidget, N + 1, FALSE);
391 XtVaSetValues ((Widget) m_mainWidget, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
395 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
399 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
401 m_inSetValue
= FALSE
;
404 bool wxListBox::Selected(int N
) const
406 // In Motif, no simple way to determine if the item is selected.
407 wxArrayInt theSelections
;
408 int count
= GetSelections (theSelections
);
414 for (j
= 0; j
< count
; j
++)
415 if (theSelections
[j
] == N
)
421 void wxListBox::Deselect(int N
)
423 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
426 char *wxListBox::GetClientData(int N
) const
428 wxNode
*node
= m_clientDataList
.Find ((long) N
);
430 return (char *) node
->Data ();
435 void wxListBox::SetClientData(int N
, char *Client_data
)
437 wxNode
*node
= m_clientDataList
.Find ((long) N
);
439 node
->SetData ((wxObject
*)Client_data
);
441 node
= m_clientDataList
.Append((long) N
, (wxObject
*) Client_data
);
444 // Return number of selections and an array of selected integers
445 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const
449 Widget listBox
= (Widget
) m_mainWidget
;
452 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
457 aSelections
.Alloc(posCnt
);
460 for (i
= 0; i
< posCnt
; i
++)
461 aSelections
.Add(posList
[i
] - 1);
463 XtFree ((char *) posList
);
473 // Get single selection, for single choice list items
474 int wxListBox::GetSelection() const
476 Widget listBox
= (Widget
) m_mainWidget
;
479 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
485 XtFree ((char *) posList
);
492 // Find string for position
493 wxString
wxListBox::GetString(int N
) const
495 Widget listBox
= (Widget
) m_mainWidget
;
498 XtVaGetValues (listBox
, XmNitemCount
, &n
, XmNitems
, &strlist
, NULL
);
499 if (N
<= n
&& N
>= 0)
502 if (XmStringGetLtoR (strlist
[N
], XmSTRING_DEFAULT_CHARSET
, &txt
))
509 return wxEmptyString
;
512 return wxEmptyString
;
515 void wxListBox::SetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
517 wxWindow::SetSize(x
, y
, width
, height
, sizeFlags
);
519 // Check resulting size is correct
521 GetSize (&tempW
, &tempH
);
524 if (tempW != width || tempH != height)
526 cout << "wxListBox::SetSize sizes not set correctly.");
531 void wxListBox::InsertItems(int nItems
, const wxString items
[], int pos
)
536 Widget listBox
= (Widget
) m_mainWidget
;
538 GetSize(&width1
, &height1
);
540 bool managed
= XtIsManaged(listBox
);
543 XtUnmanageChild(listBox
);
545 XmString
*text
= new XmString
[nItems
];
547 // Steve Hammes: Motif 1.1 compatibility
548 // #if XmVersion > 1100
549 // Corrected by Sergey Krasnov from Steve Hammes' code
551 for (i
= 0; i
< nItems
; i
++)
552 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
553 XmListAddItemsUnselected(listBox
, text
, nItems
, pos
+1);
555 for (i
= 0; i
< nItems
; i
++)
557 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
558 // XmListAddItemUnselected(listBox, text[i], i);
559 XmListAddItemUnselected(listBox
, text
[i
], pos
+i
+1); // Another Sergey correction
562 for (i
= 0; i
< nItems
; i
++)
563 XmStringFree(text
[i
]);
567 // It seems that if the list is cleared, we must re-ask for
568 // selection policy!!
570 XtSetArg(args
[0], XmNlistSizePolicy
, XmCONSTANT
);
571 if (m_windowStyle
& wxLB_MULTIPLE
)
572 XtSetArg(args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
573 else if (m_windowStyle
& wxLB_EXTENDED
)
574 XtSetArg(args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
575 else XtSetArg(args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
576 XtSetValues(listBox
,args
,2) ;
579 XtManageChild(listBox
);
581 GetSize(&width2
, &height2
);
582 // Correct for randomly resized listbox - bad boy, Motif!
583 if (width1
!= width2
/*|| height1 != height2*/)
584 SetSize(-1, -1, width1
, height1
);
589 void wxListBox::SetString(int N
, const wxString
& s
)
594 Widget listBox
= (Widget
) m_mainWidget
;
595 GetSize (&width1
, &height1
);
597 XmString text
= XmStringCreateSimple ((char*) (const char*) s
);
599 // WHAT'S THE MOTIF CALL TO SET THE TEXT OF AN EXISTING
601 // There isn't one, so delete the item and add it again.
602 XmListDeletePos (listBox
, N
+1);
603 XmListAddItem (listBox
, text
, N
+1);
608 // It seems that if the list is cleared, we must re-ask for
609 // selection policy!!
611 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
612 if (m_windowStyle & wxLB_MULTIPLE)
613 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
614 else if (m_windowStyle & wxLB_EXTENDED)
615 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
617 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
618 XtSetValues (listBox, args, 2);
621 GetSize (&width2
, &height2
);
622 // Correct for randomly resized listbox - bad boy, Motif!
623 if (width1
!= width2
|| height1
!= height2
)
624 SetSize (-1, -1, width1
, height1
);
627 int wxListBox::Number () const
632 // For single selection items only
633 wxString
wxListBox::GetStringSelection () const
635 int sel
= GetSelection ();
637 return this->GetString (sel
);
642 bool wxListBox::SetStringSelection (const wxString
& s
, bool flag
)
644 int sel
= FindString (s
);
647 SetSelection (sel
, flag
);
654 void wxListBox::Command (wxCommandEvent
& event
)
656 if (event
.m_extraLong
)
657 SetSelection (event
.m_commandInt
);
660 Deselect (event
.m_commandInt
);
663 ProcessCommand (event
);
666 void wxListBoxCallback (Widget w
, XtPointer clientData
,
667 XmListCallbackStruct
* cbs
)
670 if (cbs->reason == XmCR_EXTENDED_SELECT)
671 cout << "*** Extend select\n";
672 else if (cbs->reason == XmCR_SINGLE_SELECT)
673 cout << "*** Single select\n";
674 else if (cbs->reason == XmCR_MULTIPLE_SELECT)
675 cout << "*** Multiple select\n";
676 else if (cbs->reason == XmCR_BROWSE_SELECT)
677 cout << "*** Browse select\n";
679 if (cbs->selection_type == XmMODIFICATION)
680 cout << "*** Modification\n";
681 else if (cbs->selection_type == XmINITIAL)
682 cout << "*** Initial\n";
683 else if (cbs->selection_type == XmADDITION)
684 cout << "*** Addition\n";
687 wxListBox
*item
= (wxListBox
*) clientData
;
689 if (item
->InSetValue())
692 wxCommandEvent
event (wxEVT_COMMAND_LISTBOX_SELECTED
, item
->GetId());
695 case XmCR_MULTIPLE_SELECT
:
696 case XmCR_BROWSE_SELECT
:
698 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
699 //event.commandString = item->GetStringSelection();
700 event
.m_commandInt
= cbs
->item_position
- 1;
701 event
.m_extraLong
= TRUE
;
702 event
.SetEventObject(item
);
703 item
->ProcessCommand (event
);
704 //delete[] event.commandString; // Let's not store the command string any more
707 case XmCR_EXTENDED_SELECT
:
709 switch (cbs
->selection_type
)
715 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
716 event
.m_commandInt
= cbs
->item_position
- 1;
717 event
.m_extraLong
= TRUE
;
718 event
.SetEventObject(item
);
719 item
->ProcessCommand (event
);
728 /* Respond by getting the
729 * designated "default button" in the action area and activate it
730 * as if the user had selected it.
732 void wxListBoxDefaultActionProc (Widget list_w
, XtPointer client_data
, XmListCallbackStruct
* cbs
)
734 wxListBox
*lbox
= (wxListBox
*) client_data
;
736 wxCommandEvent
event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
, lbox
->GetId());
737 event
.SetEventObject( lbox
);
738 lbox
->GetEventHandler()->ProcessEvent(event
) ;
741 WXWidget
wxListBox::GetTopWidget() const
743 return (WXWidget
) XtParent( (Widget
) m_mainWidget
);
746 void wxListBox::ChangeFont(bool keepOriginalSize
)
748 wxWindow::ChangeFont(keepOriginalSize
);
751 void wxListBox::ChangeBackgroundColour()
753 wxWindow::ChangeBackgroundColour();
755 Widget parent
= XtParent ((Widget
) m_mainWidget
);
758 XtVaGetValues (parent
,
759 XmNhorizontalScrollBar
, &hsb
,
760 XmNverticalScrollBar
, &vsb
,
763 /* TODO: should scrollbars be affected? Should probably have separate
764 * function to change them (by default, taken from wxSystemSettings)
766 wxColour backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
);
767 DoChangeBackgroundColour((WXWidget
) hsb
, backgroundColour
, TRUE
);
768 DoChangeBackgroundColour((WXWidget
) vsb
, backgroundColour
, TRUE
);
771 XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(hsb
)),
774 XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(vsb
)),
777 DoChangeBackgroundColour((WXWidget
) parent
, m_backgroundColour
, TRUE
);
780 void wxListBox::ChangeForegroundColour()
782 wxWindow::ChangeForegroundColour();
784 Widget parent
= XtParent ((Widget
) m_mainWidget
);
787 XtVaGetValues (parent
,
788 XmNhorizontalScrollBar
, &hsb
,
789 XmNverticalScrollBar
, &vsb
,
791 /* TODO: should scrollbars be affected? Should probably have separate
792 * function to change them (by default, taken from wxSystemSettings)
793 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
794 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
795 DoChangeForegroundColour((WXWidget) parent, m_foregroundColour);