1 /////////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  13     #pragma implementation "listbox.h" 
  17 #define XtParent XTPARENT 
  18 #define XtDisplay XTDISPLAY 
  21 # include "wx/listbox.h" 
  22 #include "wx/settings.h" 
  23 #include "wx/dynarray.h" 
  28 #pragma message disable nosimpint 
  32 #pragma message enable nosimpint 
  34 #include "wx/motif/private.h" 
  36     IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControl
) 
  38 static void wxListBoxCallback(Widget w
, 
  40                               XmListCallbackStruct 
* cbs
); 
  42 // ---------------------------------------------------------------------------- 
  44 // ---------------------------------------------------------------------------- 
  46 // helper class to reduce code duplication 
  52     wxSizeKeeper( wxWindow
* w 
) 
  55         m_w
->GetSize( &m_x
, &m_y 
); 
  62         m_w
->GetSize( &x
, &y 
); 
  63         if( x 
!= m_x 
|| y 
!= m_y 
) 
  64             m_w
->SetSize( -1, -1, m_x
, m_y 
); 
  68 // ============================================================================ 
  69 // list box control implementation 
  70 // ============================================================================ 
  73 wxListBox::wxListBox() 
  78 bool wxListBox::Create(wxWindow 
*parent
, wxWindowID id
, 
  81                        int n
, const wxString choices
[], 
  83                        const wxValidator
& validator
, 
  86     if( !wxControl::CreateControl( parent
, id
, pos
, size
, style
, 
  91     m_backgroundColour 
= * wxWHITE
; 
  93     Widget parentWidget 
= (Widget
) parent
->GetClientWidget(); 
  97     XtSetArg( args
[0], XmNlistSizePolicy
, XmCONSTANT 
); ++count
; 
  98     XtSetArg( args
[1], XmNselectionPolicy
, 
  99               ( m_windowStyle 
& wxLB_MULTIPLE 
) ? XmMULTIPLE_SELECT 
: 
 100               ( m_windowStyle 
& wxLB_EXTENDED 
) ? XmEXTENDED_SELECT 
: 
 103     if( m_windowStyle 
& wxLB_ALWAYS_SB 
) 
 105         XtSetArg( args
[2], XmNscrollBarDisplayPolicy
, XmSTATIC 
); 
 109     Widget listWidget 
= XmCreateScrolledList(parentWidget
, 
 110                                              (char*)name
.c_str(), args
, count
); 
 112     m_mainWidget 
= (WXWidget
) listWidget
; 
 116     XtManageChild (listWidget
); 
 119     long height 
= size
.y
; 
 125     XtAddCallback (listWidget
, 
 126                    XmNbrowseSelectionCallback
, 
 127                    (XtCallbackProc
) wxListBoxCallback
, 
 129     XtAddCallback (listWidget
, 
 130                    XmNextendedSelectionCallback
, 
 131                    (XtCallbackProc
) wxListBoxCallback
, 
 133     XtAddCallback (listWidget
, 
 134                    XmNmultipleSelectionCallback
, 
 135                    (XtCallbackProc
) wxListBoxCallback
, 
 137     XtAddCallback (listWidget
, 
 138                    XmNdefaultActionCallback
, 
 139                    (XtCallbackProc
) wxListBoxCallback
, 
 144     SetCanAddEventHandler(TRUE
); 
 145     AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, 
 146                   pos
.x
, pos
.y
, width
, height
); 
 148     ChangeBackgroundColour(); 
 153 wxListBox::~wxListBox() 
 155     if( HasClientObjectData() ) 
 156         m_clientDataDict
.DestroyData(); 
 159 void wxListBox::SetSelectionPolicy() 
 161     Widget listBox 
= (Widget
)m_mainWidget
; 
 164     XtSetArg( args
[0], XmNlistSizePolicy
, XmCONSTANT 
); 
 166     XtSetArg( args
[1], XmNselectionPolicy
, 
 167               ( m_windowStyle 
& wxLB_MULTIPLE 
) ? XmMULTIPLE_SELECT 
: 
 168               ( m_windowStyle 
& wxLB_EXTENDED 
) ? XmEXTENDED_SELECT 
: 
 171     XtSetValues( listBox
, args
, 2 ); 
 174 void wxListBox::DoSetFirstItem( int N 
) 
 180     XtVaGetValues ((Widget
) m_mainWidget
, 
 181                     XmNvisibleItemCount
, &count
, 
 182                     XmNitemCount
, &length
, 
 184     if ((N 
+ count
) >= length
) 
 186     XmListSetPos ((Widget
) m_mainWidget
, N 
+ 1); 
 189 void wxListBox::Delete(int N
) 
 191     wxSizeKeeper 
sk( this ); 
 192     Widget listBox 
= (Widget
) m_mainWidget
; 
 194     bool managed 
= XtIsManaged(listBox
); 
 197         XtUnmanageChild (listBox
); 
 199     XmListDeletePos (listBox
, N 
+ 1); 
 202         XtManageChild (listBox
); 
 205     m_clientDataDict
.Delete(N
, HasClientObjectData()); 
 209 int wxListBox::DoAppend(const wxString
& item
) 
 211     wxSizeKeeper 
sk( this ); 
 212     Widget listBox 
= (Widget
) m_mainWidget
; 
 214     bool managed 
= XtIsManaged(listBox
); 
 217         XtUnmanageChild (listBox
); 
 219     XtVaGetValues (listBox
, XmNitemCount
, &n
, NULL
); 
 220     wxXmString 
text( item 
); 
 221     //  XmListAddItem(listBox, text, n + 1); 
 222     XmListAddItemUnselected (listBox
, text(), 0); 
 224     // It seems that if the list is cleared, we must re-ask for 
 225     // selection policy!! 
 226     SetSelectionPolicy(); 
 229         XtManageChild (listBox
); 
 234     return GetCount() - 1; 
 237 void wxListBox::DoSetItems(const wxArrayString
& items
, void** clientData
) 
 239     wxSizeKeeper 
sk( this ); 
 240     Widget listBox 
= (Widget
) m_mainWidget
; 
 242     if( HasClientObjectData() ) 
 243         m_clientDataDict
.DestroyData(); 
 245     bool managed 
= XtIsManaged(listBox
); 
 248         XtUnmanageChild (listBox
); 
 249     XmString 
*text 
= new XmString
[items
.GetCount()]; 
 251     for (i 
= 0; i 
< items
.GetCount(); ++i
) 
 252         text
[i
] = XmStringCreateSimple ((char*)items
[i
].c_str()); 
 255         for (i 
= 0; i 
< items
.GetCount(); ++i
) 
 256             m_clientDataDict
.Set(i
, (wxClientData
*)clientData
[i
], FALSE
); 
 258     XmListAddItems (listBox
, text
, items
.GetCount(), 0); 
 259     for (i 
= 0; i 
< items
.GetCount(); i
++) 
 260         XmStringFree (text
[i
]); 
 263     // It seems that if the list is cleared, we must re-ask for 
 264     // selection policy!! 
 265     SetSelectionPolicy(); 
 268         XtManageChild (listBox
); 
 272     m_noItems 
= items
.GetCount(); 
 275 int wxDoFindStringInList(Widget w
, const wxString
& s
) 
 278     int *positions 
= NULL
; 
 279     int no_positions 
= 0; 
 280     bool success 
= XmListGetMatchPos (w
, str(), 
 281                                       &positions
, &no_positions
); 
 285         int pos 
= positions
[0]; 
 287             XtFree ((char *) positions
); 
 294 int wxListBox::FindString(const wxString
& s
) const 
 296     return wxDoFindStringInList( (Widget
)m_mainWidget
, s 
); 
 299 void wxListBox::Clear() 
 304     wxSizeKeeper 
sk( this ); 
 305     Widget listBox 
= (Widget
) m_mainWidget
; 
 307     XmListDeleteAllItems (listBox
); 
 308     if( HasClientObjectData() ) 
 309         m_clientDataDict
.DestroyData(); 
 316 void wxListBox::SetSelection(int N
, bool select
) 
 322         if (m_windowStyle 
& wxLB_MULTIPLE
) 
 324             int *selections 
= NULL
; 
 325             int n 
= GetSelections (&selections
); 
 327             // This hack is supposed to work, to make it possible 
 328             // to select more than one item, but it DOESN'T under Motif 1.1. 
 330             XtVaSetValues ((Widget
) m_mainWidget
, 
 331                            XmNselectionPolicy
, XmMULTIPLE_SELECT
, 
 335             for (i 
= 0; i 
< n
; i
++) 
 336                 XmListSelectPos ((Widget
) m_mainWidget
, 
 337                                  selections
[i
] + 1, FALSE
); 
 339             XmListSelectPos ((Widget
) m_mainWidget
, N 
+ 1, FALSE
); 
 341             XtVaSetValues ((Widget
) m_mainWidget
, 
 342                            XmNselectionPolicy
, XmEXTENDED_SELECT
, 
 347             XmListSelectPos ((Widget
) m_mainWidget
, N 
+ 1, FALSE
); 
 351         XmListDeselectPos ((Widget
) m_mainWidget
, N 
+ 1); 
 353     m_inSetValue 
= FALSE
; 
 356 bool wxListBox::IsSelected(int N
) const 
 358     // In Motif, no simple way to determine if the item is selected. 
 359     wxArrayInt theSelections
; 
 360     int count 
= GetSelections (theSelections
); 
 366         for (j 
= 0; j 
< count
; j
++) 
 367             if (theSelections
[j
] == N
) 
 373 void wxListBox::DoSetItemClientObject(int n
, wxClientData
* clientData
) 
 375     m_clientDataDict
.Set(n
, clientData
, FALSE
); 
 378 wxClientData
* wxListBox::DoGetItemClientObject(int n
) const 
 380     return m_clientDataDict
.Get(n
); 
 383 void *wxListBox::DoGetItemClientData(int N
) const 
 385     return (void*)m_clientDataDict
.Get(N
); 
 388 void wxListBox::DoSetItemClientData(int N
, void *Client_data
) 
 390     m_clientDataDict
.Set(N
, (wxClientData
*)Client_data
, FALSE
); 
 393 // Return number of selections and an array of selected integers 
 394 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const 
 398     Widget listBox 
= (Widget
) m_mainWidget
; 
 401     bool flag 
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
); 
 406             aSelections
.Alloc(posCnt
); 
 409             for (i 
= 0; i 
< posCnt
; i
++) 
 410                 aSelections
.Add(posList
[i
] - 1); 
 412             XtFree ((char *) posList
); 
 422 // Get single selection, for single choice list items 
 423 int wxDoGetSelectionInList(Widget listBox
) 
 427     bool flag 
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
); 
 433         XtFree ((char *) posList
); 
 440 int wxListBox::GetSelection() const 
 442     return wxDoGetSelectionInList((Widget
) m_mainWidget
); 
 445 // Find string for position 
 446 wxString 
wxListBox::GetString(int N
) const 
 448     Widget listBox 
= (Widget
) m_mainWidget
; 
 451     XtVaGetValues (listBox
, XmNitemCount
, &n
, XmNitems
, &strlist
, NULL
); 
 452     if (N 
<= n 
&& N 
>= 0) 
 455         if (XmStringGetLtoR (strlist
[N
], XmSTRING_DEFAULT_CHARSET
, &txt
)) 
 462             return wxEmptyString
; 
 465         return wxEmptyString
; 
 468 void wxListBox::DoInsertItems(const wxArrayString
& items
, int pos
) 
 470     wxSizeKeeper 
sk( this ); 
 471     Widget listBox 
= (Widget
) m_mainWidget
; 
 473     bool managed 
= XtIsManaged(listBox
); 
 476         XtUnmanageChild(listBox
); 
 478     XmString 
*text 
= new XmString
[items
.GetCount()]; 
 480     // Steve Hammes: Motif 1.1 compatibility 
 481     // #if XmVersion > 1100 
 482     // Corrected by Sergey Krasnov from Steve Hammes' code 
 484     for (i 
= 0; i 
< items
.GetCount(); i
++) 
 485         text
[i
] = XmStringCreateSimple((char*)items
[i
].c_str()); 
 486     XmListAddItemsUnselected(listBox
, text
, items
.GetCount(), pos
+1); 
 488     for (i 
= 0; i 
< items
.GetCount(); i
++) 
 490         text
[i
] = XmStringCreateSimple((char*)items
[i
].c_str()); 
 491         // Another Sergey correction 
 492         XmListAddItemUnselected(listBox
, text
[i
], pos
+i
+1); 
 495     for (i 
= 0; i 
< items
.GetCount(); i
++) 
 496         XmStringFree(text
[i
]); 
 499     // It seems that if the list is cleared, we must re-ask for 
 500     // selection policy!! 
 501     SetSelectionPolicy(); 
 504         XtManageChild(listBox
); 
 508     m_noItems 
+= items
.GetCount(); 
 511 void wxListBox::SetString(int N
, const wxString
& s
) 
 513     wxSizeKeeper 
sk( this ); 
 514     Widget listBox 
= (Widget
) m_mainWidget
; 
 516     wxXmString 
text( s 
); 
 518     // delete the item and add it again. 
 519     // FIXME isn't there a way to change it in place? 
 520     XmListDeletePos (listBox
, N
+1); 
 521     XmListAddItem (listBox
, text(), N
+1); 
 526 void wxListBox::Command (wxCommandEvent 
& event
) 
 528     if (event
.m_extraLong
) 
 529         SetSelection (event
.m_commandInt
); 
 532         Deselect (event
.m_commandInt
); 
 535     ProcessCommand (event
); 
 538 void wxListBoxCallback (Widget 
WXUNUSED(w
), XtPointer clientData
, 
 539                         XmListCallbackStruct 
* cbs
) 
 541     wxListBox 
*item 
= (wxListBox 
*) clientData
; 
 543     if (item
->InSetValue()) 
 548     if( cbs
->reason 
== XmCR_DEFAULT_ACTION 
) 
 549         evtType 
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
; 
 551         evtType 
= wxEVT_COMMAND_LISTBOX_SELECTED
; 
 553     int n 
= cbs
->item_position 
- 1; 
 554     wxCommandEvent 
event (evtType
, item
->GetId()); 
 555     if ( item
->HasClientObjectData() ) 
 556         event
.SetClientObject( item
->GetClientObject(n
) ); 
 557     else if ( item
->HasClientUntypedData() ) 
 558         event
.SetClientData( item
->GetClientData(n
) ); 
 559     event
.m_commandInt 
= n
; 
 560     event
.m_extraLong 
= TRUE
; 
 561     event
.SetEventObject(item
); 
 562     event
.SetString( item
->GetString( n 
) ); 
 565     if( NULL 
!= cbs
->event 
&& cbs
->event
->type 
== ButtonRelease 
) 
 567         XButtonEvent
* evt 
= (XButtonEvent
*)cbs
->event
; 
 574     case XmCR_MULTIPLE_SELECT
: 
 575     case XmCR_BROWSE_SELECT
: 
 576 #if wxUSE_CHECKLISTBOX 
 577         item
->DoToggleItem( n
, x 
); 
 579     case XmCR_DEFAULT_ACTION
: 
 580         item
->GetEventHandler()->ProcessEvent(event
); 
 582     case XmCR_EXTENDED_SELECT
: 
 583         switch (cbs
->selection_type
) 
 588             item
->DoToggleItem( n
, x 
); 
 589             item
->GetEventHandler()->ProcessEvent(event
); 
 596 WXWidget 
wxListBox::GetTopWidget() const 
 598     return (WXWidget
) XtParent( (Widget
) m_mainWidget 
); 
 601 void wxListBox::ChangeBackgroundColour() 
 603     wxWindow::ChangeBackgroundColour(); 
 605     Widget parent 
= XtParent ((Widget
) m_mainWidget
); 
 608     XtVaGetValues (parent
, 
 609         XmNhorizontalScrollBar
, &hsb
, 
 610         XmNverticalScrollBar
, &vsb
, 
 613    /* TODO: should scrollbars be affected? Should probably have separate 
 614     * function to change them (by default, taken from wxSystemSettings) 
 616     wxColour backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
); 
 617     DoChangeBackgroundColour((WXWidget
) hsb
, backgroundColour
, TRUE
); 
 618     DoChangeBackgroundColour((WXWidget
) vsb
, backgroundColour
, TRUE
); 
 621         XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(hsb
)), 
 624         XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(vsb
)), 
 627     DoChangeBackgroundColour((WXWidget
) parent
, m_backgroundColour
, TRUE
); 
 630 void wxListBox::ChangeForegroundColour() 
 632     wxWindow::ChangeForegroundColour(); 
 634     Widget parent 
= XtParent ((Widget
) m_mainWidget
); 
 637     XtVaGetValues(parent
, 
 638                   XmNhorizontalScrollBar
, &hsb
, 
 639                   XmNverticalScrollBar
, &vsb
, 
 642     /* TODO: should scrollbars be affected? Should probably have separate 
 643              function to change them (by default, taken from wxSystemSettings) 
 645         DoChangeForegroundColour((WXWidget) hsb, m_foregroundColour); 
 646         DoChangeForegroundColour((WXWidget) vsb, m_foregroundColour); 
 647         DoChangeForegroundColour((WXWidget) parent, m_foregroundColour); 
 651 int wxListBox::GetCount() const