1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/motif/listbox.cpp 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  17 #include "wx/listbox.h" 
  20     #include "wx/dynarray.h" 
  23     #include "wx/settings.h" 
  24     #include "wx/arrstr.h" 
  28 #pragma message disable nosimpint 
  32 #pragma message enable nosimpint 
  34 #include "wx/motif/private.h" 
  36 static void wxListBoxCallback(Widget w
, 
  38                               XmListCallbackStruct 
* cbs
); 
  40 // ---------------------------------------------------------------------------- 
  42 // ---------------------------------------------------------------------------- 
  44 // helper class to reduce code duplication 
  51     wxSizeKeeper( wxWindow
* w 
) 
  54         m_wnd
->GetSize( &m_w
, &m_h 
); 
  55         m_wnd
->GetPosition( &m_x
, &m_y 
); 
  62         m_wnd
->GetSize( &x
, &y 
); 
  63         if( x 
!= m_x 
|| y 
!= m_y 
) 
  64             m_wnd
->SetSize( m_x
, m_y
, m_w
, m_h 
); 
  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_noItems 
= (unsigned int)n
; 
  93     Widget parentWidget 
= (Widget
) parent
->GetClientWidget(); 
  94     Display
* dpy 
= XtDisplay(parentWidget
); 
  98     XtSetArg( args
[count
], XmNlistSizePolicy
, XmCONSTANT 
); ++count
; 
  99     XtSetArg( args
[count
], XmNselectionPolicy
, 
 100               ( m_windowStyle 
& wxLB_MULTIPLE 
) ? XmMULTIPLE_SELECT 
: 
 101               ( m_windowStyle 
& wxLB_EXTENDED 
) ? XmEXTENDED_SELECT 
: 
 106         XtSetArg( args
[count
], 
 107                   (String
)wxFont::GetFontTag(), m_font
.GetFontTypeC(dpy
) ); 
 110     if( m_windowStyle 
& wxLB_ALWAYS_SB 
) 
 112         XtSetArg( args
[count
], XmNscrollBarDisplayPolicy
, XmSTATIC 
); 
 117         XmCreateScrolledList(parentWidget
, 
 118                              name
.char_str(), args
, count
); 
 120     m_mainWidget 
= (WXWidget
) listWidget
; 
 124     XtManageChild (listWidget
); 
 126     wxSize best 
= GetBestSize(); 
 127     if( size
.x 
!= -1 ) best
.x 
= size
.x
; 
 128     if( size
.y 
!= -1 ) best
.y 
= size
.y
; 
 130     XtAddCallback (listWidget
, 
 131                    XmNbrowseSelectionCallback
, 
 132                    (XtCallbackProc
) wxListBoxCallback
, 
 134     XtAddCallback (listWidget
, 
 135                    XmNextendedSelectionCallback
, 
 136                    (XtCallbackProc
) wxListBoxCallback
, 
 138     XtAddCallback (listWidget
, 
 139                    XmNmultipleSelectionCallback
, 
 140                    (XtCallbackProc
) wxListBoxCallback
, 
 142     XtAddCallback (listWidget
, 
 143                    XmNdefaultActionCallback
, 
 144                    (XtCallbackProc
) wxListBoxCallback
, 
 148     AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, 
 149                   pos
.x
, pos
.y
, best
.x
, best
.y
); 
 154 bool wxListBox::Create(wxWindow 
*parent
, wxWindowID id
, 
 157                        const wxArrayString
& choices
, 
 159                        const wxValidator
& validator
, 
 160                        const wxString
& name
) 
 162     wxCArrayString 
chs(choices
); 
 163     return Create(parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(), 
 164                   style
, validator
, name
); 
 167 void wxListBox::SetSelectionPolicy() 
 169     Widget listBox 
= (Widget
)m_mainWidget
; 
 172     XtSetArg( args
[0], XmNlistSizePolicy
, XmCONSTANT 
); 
 174     XtSetArg( args
[1], XmNselectionPolicy
, 
 175               ( m_windowStyle 
& wxLB_MULTIPLE 
) ? XmMULTIPLE_SELECT 
: 
 176               ( m_windowStyle 
& wxLB_EXTENDED 
) ? XmEXTENDED_SELECT 
: 
 179     XtSetValues( listBox
, args
, 2 ); 
 182 void wxListBox::DoSetFirstItem( int N 
) 
 189     XtVaGetValues ((Widget
) m_mainWidget
, 
 190                     XmNvisibleItemCount
, &count
, 
 191                     XmNitemCount
, &length
, 
 193     if ((N 
+ count
) >= length
) 
 195     XmListSetPos ((Widget
) m_mainWidget
, N 
+ 1); 
 198 void wxListBox::DoDeleteOneItem(unsigned int n
) 
 200     Widget listBox 
= (Widget
) m_mainWidget
; 
 202     XmListDeletePos (listBox
, n 
+ 1); 
 204     wxListBoxBase::DoDeleteOneItem(n
); 
 208 int wxDoFindStringInList(Widget w
, const wxString
& s
) 
 211     int *positions 
= NULL
; 
 212     int no_positions 
= 0; 
 213     bool success 
= XmListGetMatchPos (w
, str(), 
 214                                       &positions
, &no_positions
); 
 216     if (success 
&& positions
) 
 218         int pos 
= positions
[0]; 
 219         XtFree ((char *) positions
); 
 226 int wxListBox::FindString(const wxString
& s
, bool WXUNUSED(bCase
)) const 
 228     // FIXME: back to base class for not supported value of bCase 
 230     return wxDoFindStringInList( (Widget
)m_mainWidget
, s 
); 
 233 void wxListBox::DoClear() 
 238     wxSizeKeeper 
sk( this ); 
 239     Widget listBox 
= (Widget
) m_mainWidget
; 
 241     XmListDeleteAllItems (listBox
); 
 245     wxListBoxBase::DoClear(); 
 249 void wxListBox::DoSetSelection(int N
, bool select
) 
 255         if (m_windowStyle 
& wxLB_MULTIPLE
) 
 257             int *selections 
= NULL
; 
 258             int n 
= GetSelections (&selections
); 
 260             // This hack is supposed to work, to make it possible 
 261             // to select more than one item, but it DOESN'T under Motif 1.1. 
 263             XtVaSetValues ((Widget
) m_mainWidget
, 
 264                            XmNselectionPolicy
, XmMULTIPLE_SELECT
, 
 268             for (i 
= 0; i 
< n
; i
++) 
 269                 XmListSelectPos ((Widget
) m_mainWidget
, 
 270                                  selections
[i
] + 1, False
); 
 272             XmListSelectPos ((Widget
) m_mainWidget
, N 
+ 1, False
); 
 274             XtVaSetValues ((Widget
) m_mainWidget
, 
 275                            XmNselectionPolicy
, XmEXTENDED_SELECT
, 
 280             XmListSelectPos ((Widget
) m_mainWidget
, N 
+ 1, False
); 
 284         XmListDeselectPos ((Widget
) m_mainWidget
, N 
+ 1); 
 286     m_inSetValue 
= false; 
 289 bool wxListBox::IsSelected(int N
) const 
 291     // In Motif, no simple way to determine if the item is selected. 
 292     wxArrayInt theSelections
; 
 293     int count 
= GetSelections (theSelections
); 
 299         for (j 
= 0; j 
< count
; j
++) 
 300             if (theSelections
[j
] == N
) 
 306 // Return number of selections and an array of selected integers 
 307 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const 
 311     Widget listBox 
= (Widget
) m_mainWidget
; 
 314     bool flag 
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
); 
 319             aSelections
.Alloc(posCnt
); 
 322             for (i 
= 0; i 
< posCnt
; i
++) 
 323                 aSelections
.Add(posList
[i
] - 1); 
 325             XtFree ((char *) posList
); 
 335 // Get single selection, for single choice list items 
 336 int wxDoGetSelectionInList(Widget listBox
) 
 340     bool flag 
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
); 
 346         XtFree ((char *) posList
); 
 353 int wxListBox::GetSelection() const 
 355     return wxDoGetSelectionInList((Widget
) m_mainWidget
); 
 358 // Find string for position 
 359 wxString 
wxDoGetStringInList( Widget listBox
, int n 
) 
 363     XtVaGetValues( listBox
, 
 364                    XmNitemCount
, &count
, 
 367     if( n 
< count 
&& n 
>= 0 ) 
 368         return wxXmStringToString( strlist
[n
] ); 
 370         return wxEmptyString
; 
 373 wxString 
wxListBox::GetString(unsigned int n
) const 
 375     return wxDoGetStringInList( (Widget
)m_mainWidget
, n 
); 
 378 int wxListBox::DoInsertItems(const wxArrayStringsAdapter 
& items
, 
 380                              void **clientData
, wxClientDataType type
) 
 382     Widget listBox 
= (Widget
) m_mainWidget
; 
 384     const unsigned int numItems 
= items
.GetCount(); 
 386     XmString 
*text 
= new XmString
[numItems
]; 
 389     for (i 
= 0; i 
< numItems
; i
++) 
 391         text
[i
] = wxStringToXmString(items
[i
]); 
 393     XmListAddItemsUnselected(listBox
, text
, numItems
, GetMotifPosition(pos
)); 
 394     InsertNewItemsClientData(pos
, numItems
, clientData
, type
); 
 396     AllocClientData(numItems
); 
 398     unsigned int idx 
= pos
; 
 399     for ( i 
= 0; i 
< numItems
; i
++, idx
++ ) 
 401         text
[i
] = wxStringToXmString(items
[i
]); 
 402         XmListAddItemUnselected(listBox
, text
[i
], GetMotifPosition(idx
)); 
 403         InsertNewItemClientData(idx
, clientData
, i
, type
); 
 406     for (i 
= 0; i 
< numItems
; i
++) 
 407         XmStringFree(text
[i
]); 
 410     m_noItems 
+= numItems
; 
 412     SetSelectionPolicy(); 
 414     return pos 
+ numItems 
- 1; 
 417 void wxListBox::SetString(unsigned int n
, const wxString
& s
) 
 419     wxSizeKeeper 
sk( this ); 
 420     Widget listBox 
= (Widget
) m_mainWidget
; 
 422     wxXmString 
text( s 
); 
 424     // delete the item and add it again. 
 425     // FIXME isn't there a way to change it in place? 
 426     XmListDeletePos (listBox
, n
+1); 
 427     XmListAddItem (listBox
, text(), n
+1); 
 432 void wxListBox::Command (wxCommandEvent 
& event
) 
 434     if (event
.GetExtraLong()) 
 435         SetSelection (event
.GetInt()); 
 438         Deselect (event
.GetInt()); 
 441     ProcessCommand (event
); 
 444 void wxListBoxCallback (Widget 
WXUNUSED(w
), XtPointer clientData
, 
 445                         XmListCallbackStruct 
* cbs
) 
 447     wxListBox 
*item 
= (wxListBox 
*) clientData
; 
 449     if (item
->InSetValue()) 
 454     if( cbs
->reason 
== XmCR_DEFAULT_ACTION 
) 
 455         evtType 
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
; 
 457         evtType 
= wxEVT_COMMAND_LISTBOX_SELECTED
; 
 459     int n 
= cbs
->item_position 
- 1; 
 460     wxCommandEvent 
event (evtType
, item
->GetId()); 
 461     if ( item
->HasClientObjectData() ) 
 462         event
.SetClientObject( item
->GetClientObject(n
) ); 
 463     else if ( item
->HasClientUntypedData() ) 
 464         event
.SetClientData( item
->GetClientData(n
) ); 
 466     event
.SetExtraLong(true); 
 467     event
.SetEventObject(item
); 
 468     event
.SetString( item
->GetString( n 
) ); 
 471     if( NULL 
!= cbs
->event 
&& cbs
->event
->type 
== ButtonRelease 
) 
 473         XButtonEvent
* evt 
= (XButtonEvent
*)cbs
->event
; 
 480     case XmCR_MULTIPLE_SELECT
: 
 481     case XmCR_BROWSE_SELECT
: 
 482 #if wxUSE_CHECKLISTBOX 
 483         item
->DoToggleItem( n
, x 
); 
 485     case XmCR_DEFAULT_ACTION
: 
 486         item
->HandleWindowEvent(event
); 
 488     case XmCR_EXTENDED_SELECT
: 
 489         switch (cbs
->selection_type
) 
 494             item
->DoToggleItem( n
, x 
); 
 495             item
->HandleWindowEvent(event
); 
 502 WXWidget 
wxListBox::GetTopWidget() const 
 504     return (WXWidget
) XtParent( (Widget
) m_mainWidget 
); 
 507 void wxListBox::ChangeBackgroundColour() 
 509     wxWindow::ChangeBackgroundColour(); 
 511     Widget parent 
= XtParent ((Widget
) m_mainWidget
); 
 514     XtVaGetValues (parent
, 
 515         XmNhorizontalScrollBar
, &hsb
, 
 516         XmNverticalScrollBar
, &vsb
, 
 519    /* TODO: should scrollbars be affected? Should probably have separate 
 520     * function to change them (by default, taken from wxSystemSettings) 
 522     wxColour backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
); 
 523     wxDoChangeBackgroundColour((WXWidget
) hsb
, backgroundColour
, true); 
 524     wxDoChangeBackgroundColour((WXWidget
) vsb
, backgroundColour
, true); 
 527         XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(hsb
)), 
 530         XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(vsb
)), 
 533     // MBN: why change parent's background? It looks really ugly. 
 534     // wxDoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, true); 
 537 void wxListBox::ChangeForegroundColour() 
 539     wxWindow::ChangeForegroundColour(); 
 541     Widget parent 
= XtParent ((Widget
) m_mainWidget
); 
 544     XtVaGetValues(parent
, 
 545                   XmNhorizontalScrollBar
, &hsb
, 
 546                   XmNverticalScrollBar
, &vsb
, 
 549     /* TODO: should scrollbars be affected? Should probably have separate 
 550              function to change them (by default, taken from wxSystemSettings) 
 552         wxDoChangeForegroundColour((WXWidget) hsb, m_foregroundColour); 
 553         wxDoChangeForegroundColour((WXWidget) vsb, m_foregroundColour); 
 554         wxDoChangeForegroundColour((WXWidget) parent, m_foregroundColour); 
 558 unsigned int wxListBox::GetCount() const 
 563 #define LIST_SCROLL_SPACING 6 
 565 wxSize 
wxDoGetListBoxBestSize( Widget listWidget
, const wxWindow
* window 
) 
 568     Dimension spacing
, highlight
, xmargin
, ymargin
, shadow
; 
 572     XtVaGetValues( listWidget
, 
 574                    XmNlistSpacing
, &spacing
, 
 575                    XmNhighlightThickness
, &highlight
, 
 576                    XmNlistMarginWidth
, &xmargin
, 
 577                    XmNlistMarginHeight
, &ymargin
, 
 578                    XmNshadowThickness
, &shadow
, 
 581     for( size_t i 
= 0; i 
< (size_t)max
; ++i 
) 
 583         window
->GetTextExtent( wxDoGetStringInList( listWidget
, i 
), &x
, &y 
); 
 584         width 
= wxMax( width
, x 
); 
 587     // use some arbitrary value if there are no strings 
 592     window
->GetTextExtent( "v", &x
, &y 
); 
 594     // make it a little larger than widest string, plus the scrollbar 
 595     width 
+= wxSystemSettings::GetMetric( wxSYS_VSCROLL_X 
) 
 596         + 2 * highlight 
+ LIST_SCROLL_SPACING 
+ 2 * xmargin 
+ 2 * shadow
; 
 598     // at least 3 items, at most 10 
 599     int height 
= wxMax( 3, wxMin( 10, max 
) ) * 
 600         ( y 
+ spacing 
+ 2 * highlight 
) + 2 * ymargin 
+ 2 * shadow
; 
 602     return wxSize( width
, height 
); 
 605 wxSize 
wxListBox::DoGetBestSize() const 
 607     return wxDoGetListBoxBestSize( (Widget
)m_mainWidget
, this ); 
 610 #endif // wxUSE_LISTBOX