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_foregroundColour
= parent
->GetForegroundColour();
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
;
91 XtManageChild (listWidget
);
100 XtAddCallback (listWidget
, XmNbrowseSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
102 XtAddCallback (listWidget
, XmNextendedSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
104 XtAddCallback (listWidget
, XmNmultipleSelectionCallback
, (XtCallbackProc
) wxListBoxCallback
,
107 XtAddCallback (listWidget
, XmNdefaultActionCallback
, (XtCallbackProc
) wxListBoxDefaultActionProc
,
110 m_windowFont
= parent
->GetFont();
113 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, width
, height
);
115 ChangeBackgroundColour();
120 wxListBox::~wxListBox()
124 void wxListBox::SetFirstItem(int N
)
130 XtVaGetValues ((Widget
) m_mainWidget
,
131 XmNvisibleItemCount
, &count
,
132 XmNitemCount
, &length
,
134 if ((N
+ count
) >= length
)
136 XmListSetPos ((Widget
) m_mainWidget
, N
+ 1);
139 void wxListBox::SetFirstItem(const wxString
& s
)
141 int N
= FindString (s
);
147 void wxListBox::Delete(int N
)
151 Widget listBox
= (Widget
) m_mainWidget
;
152 GetSize (&width1
, &height1
);
154 bool managed
= XtIsManaged(listBox
);
157 XtUnmanageChild (listBox
);
159 XmListDeletePos (listBox
, N
+ 1);
162 XtManageChild (listBox
);
164 GetSize (&width2
, &height2
);
165 // Correct for randomly resized listbox - bad boy, Motif!
166 if (width1
!= width2
|| height1
!= height2
)
167 SetSize (-1, -1, width1
, height1
);
169 // (JDH) need to add code here to take care of clientDataList
170 wxNode
*node
= m_clientDataList
.Find((long)N
); // get item from list
171 if (node
) m_clientDataList
.DeleteNode(node
); // if existed then delete from list
172 node
= m_clientDataList
.First(); // we now have to adjust all keys that
173 while (node
) // are >=N+1
174 { if (node
->key
.integer
>= (long)(N
+1)) // very ugly C++ wise but no other way
175 node
->key
.integer
--; // to look at or change key value
182 void wxListBox::Append(const wxString
& item
)
187 Widget listBox
= (Widget
) m_mainWidget
;
188 GetSize (&width1
, &height1
);
190 bool managed
= XtIsManaged(listBox
);
193 XtUnmanageChild (listBox
);
195 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
196 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
197 // XmListAddItem(listBox, text, n + 1);
198 XmListAddItemUnselected (listBox
, text
, 0);
201 // It seems that if the list is cleared, we must re-ask for
202 // selection policy!!
204 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
205 if (m_windowStyle
& wxLB_MULTIPLE
)
206 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
207 else if (m_windowStyle
& wxLB_EXTENDED
)
208 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
210 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
211 XtSetValues (listBox
, args
, 2);
214 XtManageChild (listBox
);
216 GetSize (&width2
, &height2
);
217 // Correct for randomly resized listbox - bad boy, Motif!
218 if (width1
!= width2
|| height1
!= height2
)
219 SetSize (-1, -1, width1
, height1
);
223 void wxListBox::Append(const wxString
& item
, char *clientData
)
228 Widget listBox
= (Widget
) m_mainWidget
;
230 GetSize (&width1
, &height1
);
231 Bool managed
= XtIsManaged(listBox
);
234 XtUnmanageChild (listBox
);
237 XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
);
238 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
239 // XmListAddItem(listBox, text, n + 1);
240 XmListAddItemUnselected (listBox
, text
, 0);
243 // It seems that if the list is cleared, we must re-ask for
244 // selection policy!!
246 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
247 if (m_windowStyle
& wxLB_MULTIPLE
)
248 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
249 else if (m_windowStyle
& wxLB_EXTENDED
)
250 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
252 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
253 XtSetValues (listBox
, args
, 2);
255 m_clientDataList
.Append ((long) n
, (wxObject
*) clientData
);
258 XtManageChild (listBox
);
260 GetSize (&width2
, &height2
);
262 // Correct for randomly resized listbox - bad boy, Motif!
263 if (width1
!= width2
|| height1
!= height2
)
264 SetSize (-1, -1, width1
, height1
);
269 void wxListBox::Set(int n
, const wxString
*choices
, char** clientData
)
271 m_clientDataList
.Clear();
275 Widget listBox
= (Widget
) m_mainWidget
;
276 GetSize (&width1
, &height1
);
278 bool managed
= XtIsManaged(listBox
);
281 XtUnmanageChild (listBox
);
283 for (int i=0; i<n; i++)
285 XmString text = XmStringCreateSimple(choices[i]);
286 XmListAddItemUnselected(listBox, text, 0);
290 XmString
*text
= new XmString
[n
];
292 for (i
= 0; i
< n
; i
++)
293 text
[i
] = XmStringCreateSimple ((char*) (const char*) choices
[i
]);
296 for (i
= 0; i
< n
; i
++)
297 m_clientDataList
.Append ((long) i
, (wxObject
*) clientData
[i
]);
299 XmListAddItems (listBox
, text
, n
, 0);
300 for (i
= 0; i
< n
; i
++)
301 XmStringFree (text
[i
]);
304 // It seems that if the list is cleared, we must re-ask for
305 // selection policy!!
307 XtSetArg (args
[0], XmNlistSizePolicy
, XmCONSTANT
);
308 if (m_windowStyle
& wxLB_MULTIPLE
)
309 XtSetArg (args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
310 else if (m_windowStyle
& wxLB_EXTENDED
)
311 XtSetArg (args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
313 XtSetArg (args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
314 XtSetValues (listBox
, args
, 2);
317 XtManageChild (listBox
);
319 GetSize (&width2
, &height2
);
320 // Correct for randomly resized listbox - bad boy, Motif!
321 if (width1
!= width2
|| height1
!= height2
)
322 SetSize (-1, -1, width1
, height1
);
327 int wxListBox::FindString(const wxString
& s
) const
329 XmString str
= XmStringCreateSimple ((char*) (const char*) s
);
330 int *positions
= NULL
;
331 int no_positions
= 0;
332 bool success
= XmListGetMatchPos ((Widget
) m_mainWidget
, str
, &positions
, &no_positions
);
336 int pos
= positions
[0];
338 XtFree ((char *) positions
);
345 void wxListBox::Clear()
353 Widget listBox
= (Widget
) m_mainWidget
;
354 GetSize (&width1
, &height1
);
356 XmListDeleteAllItems (listBox
);
357 m_clientDataList
.Clear ();
358 GetSize (&width2
, &height2
);
360 // Correct for randomly resized listbox - bad boy, Motif!
361 if (width1
!= width2
|| height1
!= height2
)
362 SetSize (-1, -1, width1
, height1
);
367 void wxListBox::SetSelection(int N
, bool select
)
373 if (m_windowStyle & wxLB_MULTIPLE)
375 int *selections = NULL;
376 int n = GetSelections (&selections);
378 // This hack is supposed to work, to make it possible to select more
379 // than one item, but it DOESN'T under Motif 1.1.
381 XtVaSetValues ((Widget) m_mainWidget, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
384 for (i = 0; i < n; i++)
385 XmListSelectPos ((Widget) m_mainWidget, selections[i] + 1, FALSE);
387 XmListSelectPos ((Widget) m_mainWidget, N + 1, FALSE);
389 XtVaSetValues ((Widget) m_mainWidget, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
393 XmListSelectPos ((Widget
) m_mainWidget
, N
+ 1, FALSE
);
397 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
399 m_inSetValue
= FALSE
;
402 bool wxListBox::Selected(int N
) const
404 // In Motif, no simple way to determine if the item is selected.
405 wxArrayInt theSelections
;
406 int count
= GetSelections (theSelections
);
412 for (j
= 0; j
< count
; j
++)
413 if (theSelections
[j
] == N
)
419 void wxListBox::Deselect(int N
)
421 XmListDeselectPos ((Widget
) m_mainWidget
, N
+ 1);
424 char *wxListBox::GetClientData(int N
) const
426 wxNode
*node
= m_clientDataList
.Find ((long) N
);
428 return (char *) node
->Data ();
433 void wxListBox::SetClientData(int N
, char *Client_data
)
435 wxNode
*node
= m_clientDataList
.Find ((long) N
);
437 node
->SetData ((wxObject
*)Client_data
);
439 node
= m_clientDataList
.Append((long) N
, (wxObject
*) Client_data
);
442 // Return number of selections and an array of selected integers
443 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const
447 Widget listBox
= (Widget
) m_mainWidget
;
450 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
455 aSelections
.Alloc(posCnt
);
458 for (i
= 0; i
< posCnt
; i
++)
459 aSelections
.Add(posList
[i
] - 1);
461 XtFree ((char *) posList
);
471 // Get single selection, for single choice list items
472 int wxListBox::GetSelection() const
474 Widget listBox
= (Widget
) m_mainWidget
;
477 bool flag
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
);
483 XtFree ((char *) posList
);
490 // Find string for position
491 wxString
wxListBox::GetString(int N
) const
493 Widget listBox
= (Widget
) m_mainWidget
;
496 XtVaGetValues (listBox
, XmNitemCount
, &n
, XmNitems
, &strlist
, NULL
);
497 if (N
<= n
&& N
>= 0)
500 if (XmStringGetLtoR (strlist
[N
], XmSTRING_DEFAULT_CHARSET
, &txt
))
507 return wxEmptyString
;
510 return wxEmptyString
;
513 void wxListBox::SetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
515 wxWindow::SetSize(x
, y
, width
, height
, sizeFlags
);
517 // Check resulting size is correct
519 GetSize (&tempW
, &tempH
);
522 if (tempW != width || tempH != height)
524 cout << "wxListBox::SetSize sizes not set correctly.");
529 void wxListBox::InsertItems(int nItems
, const wxString items
[], int pos
)
534 Widget listBox
= (Widget
) m_mainWidget
;
536 GetSize(&width1
, &height1
);
538 bool managed
= XtIsManaged(listBox
);
541 XtUnmanageChild(listBox
);
543 XmString
*text
= new XmString
[nItems
];
545 // Steve Hammes: Motif 1.1 compatibility
546 // #if XmVersion > 1100
547 // Corrected by Sergey Krasnov from Steve Hammes' code
549 for (i
= 0; i
< nItems
; i
++)
550 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
551 XmListAddItemsUnselected(listBox
, text
, nItems
, pos
+1);
553 for (i
= 0; i
< nItems
; i
++)
555 text
[i
] = XmStringCreateSimple((char*) (const char*) items
[i
]);
556 // XmListAddItemUnselected(listBox, text[i], i);
557 XmListAddItemUnselected(listBox
, text
[i
], pos
+i
+1); // Another Sergey correction
560 for (i
= 0; i
< nItems
; i
++)
561 XmStringFree(text
[i
]);
565 // It seems that if the list is cleared, we must re-ask for
566 // selection policy!!
568 XtSetArg(args
[0], XmNlistSizePolicy
, XmCONSTANT
);
569 if (m_windowStyle
& wxLB_MULTIPLE
)
570 XtSetArg(args
[1], XmNselectionPolicy
, XmMULTIPLE_SELECT
);
571 else if (m_windowStyle
& wxLB_EXTENDED
)
572 XtSetArg(args
[1], XmNselectionPolicy
, XmEXTENDED_SELECT
);
573 else XtSetArg(args
[1], XmNselectionPolicy
, XmBROWSE_SELECT
);
574 XtSetValues(listBox
,args
,2) ;
577 XtManageChild(listBox
);
579 GetSize(&width2
, &height2
);
580 // Correct for randomly resized listbox - bad boy, Motif!
581 if (width1
!= width2
/*|| height1 != height2*/)
582 SetSize(-1, -1, width1
, height1
);
587 void wxListBox::SetString(int N
, const wxString
& s
)
592 Widget listBox
= (Widget
) m_mainWidget
;
593 GetSize (&width1
, &height1
);
595 XmString text
= XmStringCreateSimple ((char*) (const char*) s
);
597 // WHAT'S THE MOTIF CALL TO SET THE TEXT OF AN EXISTING
599 // There isn't one, so delete the item and add it again.
600 XmListDeletePos (listBox
, N
+1);
601 XmListAddItem (listBox
, text
, N
+1);
606 // It seems that if the list is cleared, we must re-ask for
607 // selection policy!!
609 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
610 if (m_windowStyle & wxLB_MULTIPLE)
611 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
612 else if (m_windowStyle & wxLB_EXTENDED)
613 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
615 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
616 XtSetValues (listBox, args, 2);
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
633 int sel
= GetSelection ();
635 return this->GetString (sel
);
640 bool wxListBox::SetStringSelection (const wxString
& s
, bool flag
)
642 int sel
= FindString (s
);
645 SetSelection (sel
, flag
);
652 void wxListBox::Command (wxCommandEvent
& event
)
654 if (event
.m_extraLong
)
655 SetSelection (event
.m_commandInt
);
658 Deselect (event
.m_commandInt
);
661 ProcessCommand (event
);
664 void wxListBoxCallback (Widget w
, XtPointer clientData
,
665 XmListCallbackStruct
* cbs
)
668 if (cbs->reason == XmCR_EXTENDED_SELECT)
669 cout << "*** Extend select\n";
670 else if (cbs->reason == XmCR_SINGLE_SELECT)
671 cout << "*** Single select\n";
672 else if (cbs->reason == XmCR_MULTIPLE_SELECT)
673 cout << "*** Multiple select\n";
674 else if (cbs->reason == XmCR_BROWSE_SELECT)
675 cout << "*** Browse select\n";
677 if (cbs->selection_type == XmMODIFICATION)
678 cout << "*** Modification\n";
679 else if (cbs->selection_type == XmINITIAL)
680 cout << "*** Initial\n";
681 else if (cbs->selection_type == XmADDITION)
682 cout << "*** Addition\n";
685 wxListBox
*item
= (wxListBox
*) clientData
;
687 if (item
->InSetValue())
690 wxCommandEvent
event (wxEVT_COMMAND_LISTBOX_SELECTED
);
693 case XmCR_MULTIPLE_SELECT
:
694 case XmCR_BROWSE_SELECT
:
696 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
697 //event.commandString = item->GetStringSelection();
698 event
.m_commandInt
= cbs
->item_position
- 1;
699 event
.m_extraLong
= TRUE
;
700 event
.SetEventObject(item
);
701 item
->ProcessCommand (event
);
702 //delete[] event.commandString; // Let's not store the command string any more
705 case XmCR_EXTENDED_SELECT
:
707 switch (cbs
->selection_type
)
713 event
.m_clientData
= item
->GetClientData (cbs
->item_position
- 1);
714 event
.m_commandInt
= cbs
->item_position
- 1;
715 event
.m_extraLong
= TRUE
;
716 event
.SetEventObject(item
);
717 item
->ProcessCommand (event
);
726 /* Respond by getting the
727 * designated "default button" in the action area and activate it
728 * as if the user had selected it.
730 void wxListBoxDefaultActionProc (Widget list_w
, XtPointer client_data
, XmListCallbackStruct
* cbs
)
732 wxListBox
*lbox
= (wxListBox
*) client_data
;
734 wxCommandEvent
event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
, lbox
->GetId());
735 event
.SetEventObject( lbox
);
736 lbox
->GetEventHandler()->ProcessEvent(event
) ;
739 WXWidget
wxListBox::GetTopWidget() const
741 return (WXWidget
) XtParent( (Widget
) m_mainWidget
);
744 void wxListBox::ChangeFont(bool keepOriginalSize
)
746 wxWindow::ChangeFont(keepOriginalSize
);
749 void wxListBox::ChangeBackgroundColour()
751 wxWindow::ChangeBackgroundColour();
753 Widget parent
= XtParent ((Widget
) m_mainWidget
);
756 XtVaGetValues (parent
,
757 XmNhorizontalScrollBar
, &hsb
,
758 XmNverticalScrollBar
, &vsb
,
761 /* TODO: should scrollbars be affected? Should probably have separate
762 * function to change them (by default, taken from wxSystemSettings)
763 DoChangeBackgroundColour((WXWidget) hsb, m_backgroundColour, TRUE);
764 DoChangeBackgroundColour((WXWidget) vsb, m_backgroundColour, TRUE);
767 DoChangeBackgroundColour((WXWidget
) parent
, m_backgroundColour
, TRUE
);
770 void wxListBox::ChangeForegroundColour()
772 wxWindow::ChangeForegroundColour();
774 Widget parent
= XtParent ((Widget
) m_mainWidget
);
777 XtVaGetValues (parent
,
778 XmNhorizontalScrollBar
, &hsb
,
779 XmNverticalScrollBar
, &vsb
,
781 /* TODO: should scrollbars be affected? Should probably have separate
782 * function to change them (by default, taken from wxSystemSettings)
783 DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
784 DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
785 DoChangeForegroundColour((WXWidget) parent, m_foregroundColour);