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
;
58 SetValidator(validator
);
60 if (parent
) parent
->AddChild(this);
62 m_windowId
= ( id
== -1 ) ? (int)NewControlId() : id
;
64 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
68 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
69 if (m_windowStyle
& wxLB_MULTIPLE
)
70 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
71 else if (m_windowStyle
& wxLB_EXTENDED
)
72 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
74 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
75 if (m_windowStyle
& wxLB_ALWAYS_SB
)
77 XtSetArg (args
[2], XmNscrollBarDisplayPolicy
, XmSTATIC
);
83 Widget listWidget
= XmCreateScrolledList (parentWidget
, (char*) (const char*) name
, args
, count
);
85 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
);
438 node
= m_clientDataList
.Append((long) N
, (wxObject
*) Client_data
);
441 // Return number of selections and an array of selected integers
442 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const
446 Widget listBox
= (Widget
) m_mainWidget
;
449 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
454 aSelections
.Alloc(posCnt
);
457 for (i
= 0; i
< posCnt
; i
++)
458 aSelections
.Add(posList
[i
] - 1);
460 XtFree ((char *) posList
);
470 // Get single selection, for single choice list items
471 int wxListBox::GetSelection() const
473 Widget listBox
= (Widget
) m_mainWidget
;
476 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
482 XtFree ((char *) posList
);
489 // Find string for position
490 wxString
wxListBox::GetString(int N
) const
492 Widget listBox
= (Widget
) m_mainWidget
;
495 XtVaGetValues (listBox
, XmNitemCount
, &n
, XmNitems
, &strlist
, NULL
);
496 if (N
<= n
&& N
>= 0)
499 if (XmStringGetLtoR (strlist
[N
], XmSTRING_DEFAULT_CHARSET
, &txt
))
506 return wxEmptyString
;
509 return wxEmptyString
;
512 void wxListBox::SetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
514 wxWindow::SetSize(x
, y
, width
, height
, sizeFlags
);
516 // Check resulting size is correct
518 GetSize (&tempW
, &tempH
);
521 if (tempW != width || tempH != height)
523 cout << "wxListBox::SetSize sizes not set correctly.");
528 void wxListBox::InsertItems(int nItems
, const wxString items
[], int pos
)
533 Widget listBox
= (Widget
) m_mainWidget
;
535 GetSize(&width1
, &height1
);
537 bool managed
= XtIsManaged(listBox
);
540 XtUnmanageChild(listBox
);
542 XmString
*text
= new XmString
[nItems
];
544 // Steve Hammes: Motif 1.1 compatibility
545 // #if XmVersion > 1100
546 // Corrected by Sergey Krasnov from Steve Hammes' code
548 for (i
= 0; i
< nItems
; i
++)
549 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
550 XmListAddItemsUnselected(listBox
, text
, nItems
, pos
+1);
552 for (i
= 0; i
< nItems
; i
++)
554 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
555 // XmListAddItemUnselected(listBox, text[i], i);
556 XmListAddItemUnselected(listBox
, text
[i
], pos
+i
+1); // Another Sergey correction
559 for (i
= 0; i
< nItems
; i
++)
560 XmStringFree(text
[i
]);
564 // It seems that if the list is cleared, we must re-ask for
565 // selection policy!!
567 XtSetArg(args
[0], XmNlistSizePolicy
, XmCONSTANT
);
568 if (m_windowStyle
& wxLB_MULTIPLE
)
569 XtSetArg(args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
570 else if (m_windowStyle
& wxLB_EXTENDED
)
571 XtSetArg(args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
572 else XtSetArg(args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
573 XtSetValues(listBox
,args
,2) ;
576 XtManageChild(listBox
);
578 GetSize(&width2
, &height2
);
579 // Correct for randomly resized listbox - bad boy, Motif!
580 if (width1
!= width2
/*|| height1 != height2*/)
581 SetSize(-1, -1, width1
, height1
);
586 void wxListBox::SetString(int N
, const wxString
& s
)
591 Widget listBox
= (Widget
) m_mainWidget
;
592 GetSize (&width1
, &height1
);
594 XmString text
= XmStringCreateSimple ((char*) (const char*) s
);
596 // WHAT'S THE MOTIF CALL TO SET THE TEXT OF AN EXISTING
598 // There isn't one, so delete the item and add it again.
599 XmListDeletePos (listBox
, N
+1);
600 XmListAddItem (listBox
, text
, N
+1);
605 // It seems that if the list is cleared, we must re-ask for
606 // selection policy!!
608 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
609 if (m_windowStyle & wxLB_MULTIPLE)
610 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
611 else if (m_windowStyle & wxLB_EXTENDED)
612 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
614 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
615 XtSetValues (listBox, args, 2);
618 GetSize (&width2
, &height2
);
619 // Correct for randomly resized listbox - bad boy, Motif!
620 if (width1
!= width2
|| height1
!= height2
)
621 SetSize (-1, -1, width1
, height1
);
624 int wxListBox::Number () const
629 // For single selection items only
630 wxString
wxListBox::GetStringSelection () const
632 int sel
= GetSelection ();
634 return this->GetString (sel
);
639 bool wxListBox::SetStringSelection (const wxString
& s
, bool flag
)
641 int sel
= FindString (s
);
644 SetSelection (sel
, flag
);
651 void wxListBox::Command (wxCommandEvent
& event
)
653 if (event
.m_extraLong
)
654 SetSelection (event
.m_commandInt
);
657 Deselect (event
.m_commandInt
);
660 ProcessCommand (event
);
663 void wxListBoxCallback (Widget w
, XtPointer clientData
,
664 XmListCallbackStruct
* cbs
)
667 if (cbs->reason == XmCR_EXTENDED_SELECT)
668 cout << "*** Extend select\n";
669 else if (cbs->reason == XmCR_SINGLE_SELECT)
670 cout << "*** Single select\n";
671 else if (cbs->reason == XmCR_MULTIPLE_SELECT)
672 cout << "*** Multiple select\n";
673 else if (cbs->reason == XmCR_BROWSE_SELECT)
674 cout << "*** Browse select\n";
676 if (cbs->selection_type == XmMODIFICATION)
677 cout << "*** Modification\n";
678 else if (cbs->selection_type == XmINITIAL)
679 cout << "*** Initial\n";
680 else if (cbs->selection_type == XmADDITION)
681 cout << "*** Addition\n";
684 wxListBox
*item
= (wxListBox
*) clientData
;
686 if (item
->InSetValue())
689 wxCommandEvent
event (wxEVT_COMMAND_LISTBOX_SELECTED
);
692 case XmCR_MULTIPLE_SELECT
:
693 case XmCR_BROWSE_SELECT
:
695 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
696 //event.commandString = item->GetStringSelection();
697 event
.m_commandInt
= cbs
->item_position
- 1;
698 event
.m_extraLong
= TRUE
;
699 event
.SetEventObject(item
);
700 item
->ProcessCommand (event
);
701 //delete[] event.commandString; // Let's not store the command string any more
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 list_w
, XtPointer client_data
, XmListCallbackStruct
* 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
);