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
)
46 bool wxListBox::Create(wxWindow
*parent
, wxWindowID id
,
49 int n
, const wxString choices
[],
51 const wxValidator
& validator
,
55 m_windowStyle
= style
;
60 SetValidator(validator
);
62 if (parent
) parent
->AddChild(this);
64 m_windowId
= ( id
== -1 ) ? (int)NewControlId() : id
;
66 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
70 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
71 if (m_windowStyle
& wxLB_MULTIPLE
)
72 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
73 else if (m_windowStyle
& wxLB_EXTENDED
)
74 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
76 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
77 if (m_windowStyle
& wxLB_ALWAYS_SB
)
79 XtSetArg (args
[2], XmNscrollBarDisplayPolicy
, XmSTATIC
);
85 Widget listWidget
= XmCreateScrolledList (parentWidget
, (char*) (const char*) name
, args
, count
);
87 m_mainWidget
= (WXWidget
) listWidget
;
89 XtManageChild (listWidget
);
98 XtAddCallback (listWidget
, XmNbrowseSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
100 XtAddCallback (listWidget
, XmNextendedSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
102 XtAddCallback (listWidget
, XmNmultipleSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
105 XtAddCallback (listWidget
, XmNdefaultActionCallback
, (XtCallbackProc
) wxListBoxDefaultActionProc
,
108 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, width
, height
);
110 wxSystemSettings settings
;
111 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW
));
113 SetFont(* parent
->GetFont());
114 ChangeColour(m_mainWidget
);
119 wxListBox::~wxListBox()
123 void wxListBox::SetFirstItem(int N
)
129 XtVaGetValues ((Widget
) m_mainWidget
,
130 XmNvisibleItemCount
, &count
,
131 XmNitemCount
, &length
,
133 if ((N
+ count
) >= length
)
135 XmListSetPos ((Widget
) m_mainWidget
, N
+ 1);
138 void wxListBox::SetFirstItem(const wxString
& s
)
140 int N
= FindString (s
);
146 void wxListBox::Delete(int N
)
150 Widget listBox
= (Widget
) m_mainWidget
;
151 GetSize (&width1
, &height1
);
153 bool managed
= XtIsManaged(listBox
);
156 XtUnmanageChild (listBox
);
158 XmListDeletePos (listBox
, N
+ 1);
161 XtManageChild (listBox
);
163 GetSize (&width2
, &height2
);
164 // Correct for randomly resized listbox - bad boy, Motif!
165 if (width1
!= width2
|| height1
!= height2
)
166 SetSize (-1, -1, width1
, height1
);
168 // (JDH) need to add code here to take care of clientDataList
169 wxNode
*node
= m_clientDataList
.Find((long)N
); // get item from list
170 if (node
) m_clientDataList
.DeleteNode(node
); // if existed then delete from list
171 node
= m_clientDataList
.First(); // we now have to adjust all keys that
172 while (node
) // are >=N+1
173 { if (node
->key
.integer
>= (long)(N
+1)) // very ugly C++ wise but no other way
174 node
->key
.integer
--; // to look at or change key value
181 void wxListBox::Append(const wxString
& item
)
186 Widget listBox
= (Widget
) m_mainWidget
;
187 GetSize (&width1
, &height1
);
189 bool managed
= XtIsManaged(listBox
);
192 XtUnmanageChild (listBox
);
194 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
195 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
196 // XmListAddItem(listBox, text, n + 1);
197 XmListAddItemUnselected (listBox
, text
, 0);
200 // It seems that if the list is cleared, we must re-ask for
201 // selection policy!!
203 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
204 if (m_windowStyle
& wxLB_MULTIPLE
)
205 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
206 else if (m_windowStyle
& wxLB_EXTENDED
)
207 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
209 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
210 XtSetValues (listBox
, args
, 2);
213 XtManageChild (listBox
);
215 GetSize (&width2
, &height2
);
216 // Correct for randomly resized listbox - bad boy, Motif!
217 if (width1
!= width2
|| height1
!= height2
)
218 SetSize (-1, -1, width1
, height1
);
222 void wxListBox::Append(const wxString
& item
, char *clientData
)
227 Widget listBox
= (Widget
) m_mainWidget
;
229 GetSize (&width1
, &height1
);
230 Bool managed
= XtIsManaged(listBox
);
233 XtUnmanageChild (listBox
);
236 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
237 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
238 // XmListAddItem(listBox, text, n + 1);
239 XmListAddItemUnselected (listBox
, text
, 0);
242 // It seems that if the list is cleared, we must re-ask for
243 // selection policy!!
245 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
246 if (m_windowStyle
& wxLB_MULTIPLE
)
247 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
248 else if (m_windowStyle
& wxLB_EXTENDED
)
249 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
251 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
252 XtSetValues (listBox
, args
, 2);
254 m_clientDataList
.Append ((long) n
, (wxObject
*) clientData
);
257 XtManageChild (listBox
);
259 GetSize (&width2
, &height2
);
261 // Correct for randomly resized listbox - bad boy, Motif!
262 if (width1
!= width2
|| height1
!= height2
)
263 SetSize (-1, -1, width1
, height1
);
268 void wxListBox::Set(int n
, const wxString
*choices
, char** clientData
)
270 m_clientDataList
.Clear();
274 Widget listBox
= (Widget
) m_mainWidget
;
275 GetSize (&width1
, &height1
);
277 bool managed
= XtIsManaged(listBox
);
280 XtUnmanageChild (listBox
);
282 for (int i=0; i<n; i++)
284 XmString text = XmStringCreateSimple(choices[i]);
285 XmListAddItemUnselected(listBox, text, 0);
289 XmString
*text
= new XmString
[n
];
291 for (i
= 0; i
< n
; i
++)
292 text
[i
] = XmStringCreateSimple ((char*) (const char*) choices
[i
]);
295 for (i
= 0; i
< n
; i
++)
296 m_clientDataList
.Append ((long) i
, (wxObject
*) clientData
[i
]);
298 XmListAddItems (listBox
, text
, n
, 0);
299 for (i
= 0; i
< n
; i
++)
300 XmStringFree (text
[i
]);
303 // It seems that if the list is cleared, we must re-ask for
304 // selection policy!!
306 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
307 if (m_windowStyle
& wxLB_MULTIPLE
)
308 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
309 else if (m_windowStyle
& wxLB_EXTENDED
)
310 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
312 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
313 XtSetValues (listBox
, args
, 2);
316 XtManageChild (listBox
);
318 GetSize (&width2
, &height2
);
319 // Correct for randomly resized listbox - bad boy, Motif!
320 if (width1
!= width2
|| height1
!= height2
)
321 SetSize (-1, -1, width1
, height1
);
326 int wxListBox::FindString(const wxString
& s
) const
328 XmString str
= XmStringCreateSimple ((char*) (const char*) s
);
329 int *positions
= NULL
;
330 int no_positions
= 0;
331 bool success
= XmListGetMatchPos ((Widget
) m_mainWidget
, str
, &positions
, &no_positions
);
335 int pos
= positions
[0];
337 XtFree ((char *) positions
);
344 void wxListBox::Clear()
352 Widget listBox
= (Widget
) m_mainWidget
;
353 GetSize (&width1
, &height1
);
355 XmListDeleteAllItems (listBox
);
356 m_clientDataList
.Clear ();
357 GetSize (&width2
, &height2
);
359 // Correct for randomly resized listbox - bad boy, Motif!
360 if (width1
!= width2
|| height1
!= height2
)
361 SetSize (-1, -1, width1
, height1
);
366 void wxListBox::SetSelection(int N
, bool select
)
372 if (m_windowStyle & wxLB_MULTIPLE)
374 int *selections = NULL;
375 int n = GetSelections (&selections);
377 // This hack is supposed to work, to make it possible to select more
378 // than one item, but it DOESN'T under Motif 1.1.
380 XtVaSetValues ((Widget) m_mainWidget, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
383 for (i = 0; i < n; i++)
384 XmListSelectPos ((Widget) m_mainWidget, selections[i] + 1, FALSE);
386 XmListSelectPos ((Widget) m_mainWidget, N + 1, FALSE);
388 XtVaSetValues ((Widget) m_mainWidget, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
392 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
396 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
398 m_inSetValue
= FALSE
;
401 bool wxListBox::Selected(int N
) const
403 // In Motif, no simple way to determine if the item is selected.
404 wxArrayInt theSelections
;
405 int count
= GetSelections (theSelections
);
411 for (j
= 0; j
< count
; j
++)
412 if (theSelections
[j
] == N
)
418 void wxListBox::Deselect(int N
)
420 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
423 char *wxListBox::GetClientData(int N
) const
425 wxNode
*node
= m_clientDataList
.Find ((long) N
);
427 return (char *) node
->Data ();
432 void wxListBox::SetClientData(int N
, char *Client_data
)
434 wxNode
*node
= m_clientDataList
.Find ((long) N
);
436 node
->SetData ((wxObject
*)Client_data
);
439 // Return number of selections and an array of selected integers
440 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const
444 Widget listBox
= (Widget
) m_mainWidget
;
447 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
452 aSelections
.Alloc(posCnt
);
455 for (i
= 0; i
< posCnt
; i
++)
456 aSelections
.Add(posList
[i
] - 1);
458 XtFree ((char *) posList
);
468 // Get single selection, for single choice list items
469 int wxListBox::GetSelection() const
471 Widget listBox
= (Widget
) m_mainWidget
;
474 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
480 XtFree ((char *) posList
);
487 // Find string for position
488 wxString
wxListBox::GetString(int N
) const
490 Widget listBox
= (Widget
) m_mainWidget
;
493 XtVaGetValues (listBox
, XmNitemCount
, &n
, XmNitems
, &strlist
, NULL
);
494 if (N
<= n
&& N
>= 0)
497 if (XmStringGetLtoR (strlist
[N
], XmSTRING_DEFAULT_CHARSET
, &txt
))
504 return wxEmptyString
;
507 return wxEmptyString
;
510 void wxListBox::SetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
512 wxWindow::SetSize(x
, y
, width
, height
, sizeFlags
);
514 // Check resulting size is correct
516 GetSize (&tempW
, &tempH
);
519 if (tempW != width || tempH != height)
521 cout << "wxListBox::SetSize sizes not set correctly.");
526 void wxListBox::InsertItems(int nItems
, const wxString items
[], int pos
)
531 Widget listBox
= (Widget
) m_mainWidget
;
533 GetSize(&width1
, &height1
);
535 bool managed
= XtIsManaged(listBox
);
538 XtUnmanageChild(listBox
);
540 XmString
*text
= new XmString
[nItems
];
542 // Steve Hammes: Motif 1.1 compatibility
543 // #if XmVersion > 1100
544 // Corrected by Sergey Krasnov from Steve Hammes' code
546 for (i
= 0; i
< nItems
; i
++)
547 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
548 XmListAddItemsUnselected(listBox
, text
, nItems
, pos
+1);
550 for (i
= 0; i
< nItems
; i
++)
552 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
553 // XmListAddItemUnselected(listBox, text[i], i);
554 XmListAddItemUnselected(listBox
, text
[i
], pos
+i
+1); // Another Sergey correction
557 for (i
= 0; i
< nItems
; i
++)
558 XmStringFree(text
[i
]);
562 // It seems that if the list is cleared, we must re-ask for
563 // selection policy!!
565 XtSetArg(args
[0], XmNlistSizePolicy
, XmCONSTANT
);
566 if (m_windowStyle
& wxLB_MULTIPLE
)
567 XtSetArg(args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
568 else if (m_windowStyle
& wxLB_EXTENDED
)
569 XtSetArg(args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
570 else XtSetArg(args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
571 XtSetValues(listBox
,args
,2) ;
574 XtManageChild(listBox
);
576 GetSize(&width2
, &height2
);
577 // Correct for randomly resized listbox - bad boy, Motif!
578 if (width1
!= width2
/*|| height1 != height2*/)
579 SetSize(-1, -1, width1
, height1
);
584 void wxListBox::SetString(int N
, const wxString
& s
)
589 Widget listBox
= (Widget
) m_mainWidget
;
590 GetSize (&width1
, &height1
);
592 XmString text
= XmStringCreateSimple ((char*) (const char*) s
);
594 // WHAT'S THE MOTIF CALL TO SET THE TEXT OF AN EXISTING
596 // There isn't one, so delete the item and add it again.
597 XmListDeletePos (listBox
, N
+1);
598 XmListAddItem (listBox
, text
, N
+1);
603 // It seems that if the list is cleared, we must re-ask for
604 // selection policy!!
606 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
607 if (m_windowStyle & wxLB_MULTIPLE)
608 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
609 else if (m_windowStyle & wxLB_EXTENDED)
610 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
612 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
613 XtSetValues (listBox, args, 2);
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
630 int sel
= GetSelection ();
632 return this->GetString (sel
);
637 bool wxListBox::SetStringSelection (const wxString
& s
, bool flag
)
639 int sel
= FindString (s
);
642 SetSelection (sel
, flag
);
649 void wxListBox::Command (wxCommandEvent
& event
)
651 if (event
.m_extraLong
)
652 SetSelection (event
.m_commandInt
);
655 Deselect (event
.m_commandInt
);
658 ProcessCommand (event
);
661 void wxListBoxCallback (Widget w
, XtPointer clientData
,
662 XmListCallbackStruct
* cbs
)
665 if (cbs->reason == XmCR_EXTENDED_SELECT)
666 cout << "*** Extend select\n";
667 else if (cbs->reason == XmCR_SINGLE_SELECT)
668 cout << "*** Single select\n";
669 else if (cbs->reason == XmCR_MULTIPLE_SELECT)
670 cout << "*** Multiple select\n";
671 else if (cbs->reason == XmCR_BROWSE_SELECT)
672 cout << "*** Browse select\n";
674 if (cbs->selection_type == XmMODIFICATION)
675 cout << "*** Modification\n";
676 else if (cbs->selection_type == XmINITIAL)
677 cout << "*** Initial\n";
678 else if (cbs->selection_type == XmADDITION)
679 cout << "*** Addition\n";
682 wxListBox
*item
= (wxListBox
*) clientData
;
684 if (item
->m_inSetValue
)
687 wxCommandEvent
event (wxEVT_COMMAND_LISTBOX_SELECTED
);
690 case XmCR_MULTIPLE_SELECT
:
691 case XmCR_BROWSE_SELECT
:
693 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
694 //event.commandString = item->GetStringSelection();
695 event
.m_commandInt
= cbs
->item_position
- 1;
696 event
.m_extraLong
= TRUE
;
697 event
.SetEventObject(item
);
698 item
->ProcessCommand (event
);
699 //delete[] event.commandString; // Let's not store the command string any more
702 case XmCR_EXTENDED_SELECT
:
704 switch (cbs
->selection_type
)
710 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
711 event
.m_commandInt
= cbs
->item_position
- 1;
712 event
.m_extraLong
= TRUE
;
713 event
.SetEventObject(item
);
714 item
->ProcessCommand (event
);
723 /* Respond by getting the
724 * designated "default button" in the action area and activate it
725 * as if the user had selected it.
727 void wxListBoxDefaultActionProc (Widget list_w
, XtPointer client_data
, XmListCallbackStruct
* cbs
)
729 wxListBox
*lbox
= (wxListBox
*) client_data
;
731 wxCommandEvent
event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
, lbox
->GetId());
732 event
.SetEventObject( lbox
);
733 lbox
->GetEventHandler()->ProcessEvent(event
) ;
736 WXWidget
wxListBox::GetTopWidget() const
738 return (WXWidget
) XtParent( (Widget
) m_mainWidget
);