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 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControlWithItems
) 
  38 static void wxListBoxCallback(Widget w
, 
  40                               XmListCallbackStruct 
* cbs
); 
  42 // ---------------------------------------------------------------------------- 
  44 // ---------------------------------------------------------------------------- 
  46 // helper class to reduce code duplication 
  53     wxSizeKeeper( wxWindow
* w 
) 
  56         m_wnd
->GetSize( &m_w
, &m_h 
); 
  57         m_wnd
->GetPosition( &m_x
, &m_y 
); 
  64         m_wnd
->GetSize( &x
, &y 
); 
  65         if( x 
!= m_x 
|| y 
!= m_y 
) 
  66             m_wnd
->SetSize( m_x
, m_y
, m_w
, m_h 
); 
  70 // ============================================================================ 
  71 // list box control implementation 
  72 // ============================================================================ 
  75 wxListBox::wxListBox() 
  80 bool wxListBox::Create(wxWindow 
*parent
, wxWindowID id
, 
  83                        int n
, const wxString choices
[], 
  85                        const wxValidator
& validator
, 
  88     if( !wxControl::CreateControl( parent
, id
, pos
, size
, style
, 
  93     m_noItems 
= (unsigned int)n
; 
  95     Widget parentWidget 
= (Widget
) parent
->GetClientWidget(); 
  96     Display
* dpy 
= XtDisplay(parentWidget
); 
 100     XtSetArg( args
[count
], XmNlistSizePolicy
, XmCONSTANT 
); ++count
; 
 101     XtSetArg( args
[count
], XmNselectionPolicy
, 
 102               ( m_windowStyle 
& wxLB_MULTIPLE 
) ? XmMULTIPLE_SELECT 
: 
 103               ( m_windowStyle 
& wxLB_EXTENDED 
) ? XmEXTENDED_SELECT 
: 
 108         XtSetArg( args
[count
], 
 109                   (String
)wxFont::GetFontTag(), m_font
.GetFontTypeC(dpy
) ); 
 112     if( m_windowStyle 
& wxLB_ALWAYS_SB 
) 
 114         XtSetArg( args
[count
], XmNscrollBarDisplayPolicy
, XmSTATIC 
); 
 119         XmCreateScrolledList(parentWidget
, 
 120                              name
.char_str(), args
, count
); 
 122     m_mainWidget 
= (WXWidget
) listWidget
; 
 126     XtManageChild (listWidget
); 
 128     wxSize best 
= GetBestSize(); 
 129     if( size
.x 
!= -1 ) best
.x 
= size
.x
; 
 130     if( size
.y 
!= -1 ) best
.y 
= size
.y
; 
 132     XtAddCallback (listWidget
, 
 133                    XmNbrowseSelectionCallback
, 
 134                    (XtCallbackProc
) wxListBoxCallback
, 
 136     XtAddCallback (listWidget
, 
 137                    XmNextendedSelectionCallback
, 
 138                    (XtCallbackProc
) wxListBoxCallback
, 
 140     XtAddCallback (listWidget
, 
 141                    XmNmultipleSelectionCallback
, 
 142                    (XtCallbackProc
) wxListBoxCallback
, 
 144     XtAddCallback (listWidget
, 
 145                    XmNdefaultActionCallback
, 
 146                    (XtCallbackProc
) wxListBoxCallback
, 
 150     AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, 
 151                   pos
.x
, pos
.y
, best
.x
, best
.y
); 
 156 bool wxListBox::Create(wxWindow 
*parent
, wxWindowID id
, 
 159                        const wxArrayString
& choices
, 
 161                        const wxValidator
& validator
, 
 162                        const wxString
& name
) 
 164     wxCArrayString 
chs(choices
); 
 165     return Create(parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(), 
 166                   style
, validator
, name
); 
 169 void wxListBox::SetSelectionPolicy() 
 171     Widget listBox 
= (Widget
)m_mainWidget
; 
 174     XtSetArg( args
[0], XmNlistSizePolicy
, XmCONSTANT 
); 
 176     XtSetArg( args
[1], XmNselectionPolicy
, 
 177               ( m_windowStyle 
& wxLB_MULTIPLE 
) ? XmMULTIPLE_SELECT 
: 
 178               ( m_windowStyle 
& wxLB_EXTENDED 
) ? XmEXTENDED_SELECT 
: 
 181     XtSetValues( listBox
, args
, 2 ); 
 184 void wxListBox::DoSetFirstItem( int N 
) 
 191     XtVaGetValues ((Widget
) m_mainWidget
, 
 192                     XmNvisibleItemCount
, &count
, 
 193                     XmNitemCount
, &length
, 
 195     if ((N 
+ count
) >= length
) 
 197     XmListSetPos ((Widget
) m_mainWidget
, N 
+ 1); 
 200 void wxListBox::DoDeleteOneItem(unsigned int n
) 
 202     Widget listBox 
= (Widget
) m_mainWidget
; 
 204     XmListDeletePos (listBox
, n 
+ 1); 
 206     wxListBoxBase::DoDeleteOneItem(n
); 
 210 int wxDoFindStringInList(Widget w
, const wxString
& s
) 
 213     int *positions 
= NULL
; 
 214     int no_positions 
= 0; 
 215     bool success 
= XmListGetMatchPos (w
, str(), 
 216                                       &positions
, &no_positions
); 
 218     if (success 
&& positions
) 
 220         int pos 
= positions
[0]; 
 221         XtFree ((char *) positions
); 
 228 int wxListBox::FindString(const wxString
& s
, bool WXUNUSED(bCase
)) const 
 230     // FIXME: back to base class for not supported value of bCase 
 232     return wxDoFindStringInList( (Widget
)m_mainWidget
, s 
); 
 235 void wxListBox::DoClear() 
 240     wxSizeKeeper 
sk( this ); 
 241     Widget listBox 
= (Widget
) m_mainWidget
; 
 243     XmListDeleteAllItems (listBox
); 
 247     wxListBoxBase::DoClear(); 
 251 void wxListBox::DoSetSelection(int N
, bool select
) 
 257         if (m_windowStyle 
& wxLB_MULTIPLE
) 
 259             int *selections 
= NULL
; 
 260             int n 
= GetSelections (&selections
); 
 262             // This hack is supposed to work, to make it possible 
 263             // to select more than one item, but it DOESN'T under Motif 1.1. 
 265             XtVaSetValues ((Widget
) m_mainWidget
, 
 266                            XmNselectionPolicy
, XmMULTIPLE_SELECT
, 
 270             for (i 
= 0; i 
< n
; i
++) 
 271                 XmListSelectPos ((Widget
) m_mainWidget
, 
 272                                  selections
[i
] + 1, False
); 
 274             XmListSelectPos ((Widget
) m_mainWidget
, N 
+ 1, False
); 
 276             XtVaSetValues ((Widget
) m_mainWidget
, 
 277                            XmNselectionPolicy
, XmEXTENDED_SELECT
, 
 282             XmListSelectPos ((Widget
) m_mainWidget
, N 
+ 1, False
); 
 286         XmListDeselectPos ((Widget
) m_mainWidget
, N 
+ 1); 
 288     m_inSetValue 
= false; 
 291 bool wxListBox::IsSelected(int N
) const 
 293     // In Motif, no simple way to determine if the item is selected. 
 294     wxArrayInt theSelections
; 
 295     int count 
= GetSelections (theSelections
); 
 301         for (j 
= 0; j 
< count
; j
++) 
 302             if (theSelections
[j
] == N
) 
 308 // Return number of selections and an array of selected integers 
 309 int wxListBox::GetSelections(wxArrayInt
& aSelections
) const 
 313     Widget listBox 
= (Widget
) m_mainWidget
; 
 316     bool flag 
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
); 
 321             aSelections
.Alloc(posCnt
); 
 324             for (i 
= 0; i 
< posCnt
; i
++) 
 325                 aSelections
.Add(posList
[i
] - 1); 
 327             XtFree ((char *) posList
); 
 337 // Get single selection, for single choice list items 
 338 int wxDoGetSelectionInList(Widget listBox
) 
 342     bool flag 
= XmListGetSelectedPos (listBox
, &posList
, &posCnt
); 
 348         XtFree ((char *) posList
); 
 355 int wxListBox::GetSelection() const 
 357     return wxDoGetSelectionInList((Widget
) m_mainWidget
); 
 360 // Find string for position 
 361 wxString 
wxDoGetStringInList( Widget listBox
, int n 
) 
 365     XtVaGetValues( listBox
, 
 366                    XmNitemCount
, &count
, 
 369     if( n 
< count 
&& n 
>= 0 ) 
 370         return wxXmStringToString( strlist
[n
] ); 
 372         return wxEmptyString
; 
 375 wxString 
wxListBox::GetString(unsigned int n
) const 
 377     return wxDoGetStringInList( (Widget
)m_mainWidget
, n 
); 
 380 int wxListBox::DoInsertItems(const wxArrayStringsAdapter 
& items
, 
 382                              void **clientData
, wxClientDataType type
) 
 384     Widget listBox 
= (Widget
) m_mainWidget
; 
 386     const unsigned int numItems 
= items
.GetCount(); 
 388     XmString 
*text 
= new XmString
[numItems
]; 
 391     for (i 
= 0; i 
< numItems
; i
++) 
 393         text
[i
] = wxStringToXmString(items
[i
]); 
 395     XmListAddItemsUnselected(listBox
, text
, numItems
, GetMotifPosition(pos
)); 
 396     InsertNewItemsClientData(pos
, numItems
, clientData
, type
); 
 398     AllocClientData(numItems
); 
 400     unsigned int idx 
= pos
; 
 401     for ( i 
= 0; i 
< numItems
; i
++, idx
++ ) 
 403         text
[i
] = wxStringToXmString(items
[i
]); 
 404         XmListAddItemUnselected(listBox
, text
[i
], GetMotifPosition(idx
)); 
 405         InsertNewItemClientData(idx
, clientData
, i
, type
); 
 408     for (i 
= 0; i 
< numItems
; i
++) 
 409         XmStringFree(text
[i
]); 
 412     m_noItems 
+= numItems
; 
 414     SetSelectionPolicy(); 
 416     return pos 
+ numItems 
- 1; 
 419 void wxListBox::SetString(unsigned int n
, const wxString
& s
) 
 421     wxSizeKeeper 
sk( this ); 
 422     Widget listBox 
= (Widget
) m_mainWidget
; 
 424     wxXmString 
text( s 
); 
 426     // delete the item and add it again. 
 427     // FIXME isn't there a way to change it in place? 
 428     XmListDeletePos (listBox
, n
+1); 
 429     XmListAddItem (listBox
, text(), n
+1); 
 434 void wxListBox::Command (wxCommandEvent 
& event
) 
 436     if (event
.GetExtraLong()) 
 437         SetSelection (event
.GetInt()); 
 440         Deselect (event
.GetInt()); 
 443     ProcessCommand (event
); 
 446 void wxListBoxCallback (Widget 
WXUNUSED(w
), XtPointer clientData
, 
 447                         XmListCallbackStruct 
* cbs
) 
 449     wxListBox 
*item 
= (wxListBox 
*) clientData
; 
 451     if (item
->InSetValue()) 
 456     if( cbs
->reason 
== XmCR_DEFAULT_ACTION 
) 
 457         evtType 
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
; 
 459         evtType 
= wxEVT_COMMAND_LISTBOX_SELECTED
; 
 461     int n 
= cbs
->item_position 
- 1; 
 462     wxCommandEvent 
event (evtType
, item
->GetId()); 
 463     if ( item
->HasClientObjectData() ) 
 464         event
.SetClientObject( item
->GetClientObject(n
) ); 
 465     else if ( item
->HasClientUntypedData() ) 
 466         event
.SetClientData( item
->GetClientData(n
) ); 
 468     event
.SetExtraLong(true); 
 469     event
.SetEventObject(item
); 
 470     event
.SetString( item
->GetString( n 
) ); 
 473     if( NULL 
!= cbs
->event 
&& cbs
->event
->type 
== ButtonRelease 
) 
 475         XButtonEvent
* evt 
= (XButtonEvent
*)cbs
->event
; 
 482     case XmCR_MULTIPLE_SELECT
: 
 483     case XmCR_BROWSE_SELECT
: 
 484 #if wxUSE_CHECKLISTBOX 
 485         item
->DoToggleItem( n
, x 
); 
 487     case XmCR_DEFAULT_ACTION
: 
 488         item
->HandleWindowEvent(event
); 
 490     case XmCR_EXTENDED_SELECT
: 
 491         switch (cbs
->selection_type
) 
 496             item
->DoToggleItem( n
, x 
); 
 497             item
->HandleWindowEvent(event
); 
 504 WXWidget 
wxListBox::GetTopWidget() const 
 506     return (WXWidget
) XtParent( (Widget
) m_mainWidget 
); 
 509 void wxListBox::ChangeBackgroundColour() 
 511     wxWindow::ChangeBackgroundColour(); 
 513     Widget parent 
= XtParent ((Widget
) m_mainWidget
); 
 516     XtVaGetValues (parent
, 
 517         XmNhorizontalScrollBar
, &hsb
, 
 518         XmNverticalScrollBar
, &vsb
, 
 521    /* TODO: should scrollbars be affected? Should probably have separate 
 522     * function to change them (by default, taken from wxSystemSettings) 
 524     wxColour backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
); 
 525     wxDoChangeBackgroundColour((WXWidget
) hsb
, backgroundColour
, true); 
 526     wxDoChangeBackgroundColour((WXWidget
) vsb
, backgroundColour
, true); 
 529         XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(hsb
)), 
 532         XmNtroughColor
, backgroundColour
.AllocColour(XtDisplay(vsb
)), 
 535     // MBN: why change parent's background? It looks really ugly. 
 536     // wxDoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, true); 
 539 void wxListBox::ChangeForegroundColour() 
 541     wxWindow::ChangeForegroundColour(); 
 543     Widget parent 
= XtParent ((Widget
) m_mainWidget
); 
 546     XtVaGetValues(parent
, 
 547                   XmNhorizontalScrollBar
, &hsb
, 
 548                   XmNverticalScrollBar
, &vsb
, 
 551     /* TODO: should scrollbars be affected? Should probably have separate 
 552              function to change them (by default, taken from wxSystemSettings) 
 554         wxDoChangeForegroundColour((WXWidget) hsb, m_foregroundColour); 
 555         wxDoChangeForegroundColour((WXWidget) vsb, m_foregroundColour); 
 556         wxDoChangeForegroundColour((WXWidget) parent, m_foregroundColour); 
 560 unsigned int wxListBox::GetCount() const 
 565 #define LIST_SCROLL_SPACING 6 
 567 wxSize 
wxDoGetListBoxBestSize( Widget listWidget
, const wxWindow
* window 
) 
 570     Dimension spacing
, highlight
, xmargin
, ymargin
, shadow
; 
 574     XtVaGetValues( listWidget
, 
 576                    XmNlistSpacing
, &spacing
, 
 577                    XmNhighlightThickness
, &highlight
, 
 578                    XmNlistMarginWidth
, &xmargin
, 
 579                    XmNlistMarginHeight
, &ymargin
, 
 580                    XmNshadowThickness
, &shadow
, 
 583     for( size_t i 
= 0; i 
< (size_t)max
; ++i 
) 
 585         window
->GetTextExtent( wxDoGetStringInList( listWidget
, i 
), &x
, &y 
); 
 586         width 
= wxMax( width
, x 
); 
 589     // use some arbitrary value if there are no strings 
 594     window
->GetTextExtent( "v", &x
, &y 
); 
 596     // make it a little larger than widest string, plus the scrollbar 
 597     width 
+= wxSystemSettings::GetMetric( wxSYS_VSCROLL_X 
) 
 598         + 2 * highlight 
+ LIST_SCROLL_SPACING 
+ 2 * xmargin 
+ 2 * shadow
; 
 600     // at least 3 items, at most 10 
 601     int height 
= wxMax( 3, wxMin( 10, max 
) ) * 
 602         ( y 
+ spacing 
+ 2 * highlight 
) + 2 * ymargin 
+ 2 * shadow
; 
 604     return wxSize( width
, height 
); 
 607 wxSize 
wxListBox::DoGetBestSize() const 
 609     return wxDoGetListBoxBestSize( (Widget
)m_mainWidget
, this ); 
 612 #endif // wxUSE_LISTBOX