1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/os2/listbox.cpp 
   4 // Author:      David Webster 
   8 // Copyright:   (c) David Webster 
   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" 
  21     #include "wx/settings.h" 
  25     #include "wx/dcscreen.h" 
  27     #include "wx/scrolwin.h" 
  29     #include "wx/window.h" 
  32 #include "wx/os2/private.h" 
  38     #include  "wx/ownerdrw.h" 
  41 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControlWithItems
) 
  43 // ============================================================================ 
  44 // list box item declaration and implementation 
  45 // ============================================================================ 
  49 class wxListBoxItem 
: public wxOwnerDrawn
 
  52     wxListBoxItem(const wxString
& rsStr 
= wxEmptyString
); 
  55 wxListBoxItem::wxListBoxItem( 
  63     // No bitmaps/checkmarks 
  66 } // end of wxListBoxItem::wxListBoxItem 
  68 wxOwnerDrawn
* wxListBox::CreateItem( size_t WXUNUSED(n
) ) 
  70     return new wxListBoxItem(); 
  71 } // end of wxListBox::CreateItem 
  73 #endif  //USE_OWNER_DRAWN 
  75 // ============================================================================ 
  76 // list box control implementation 
  77 // ============================================================================ 
  80 wxListBox::wxListBox() 
  84 } // end of wxListBox::wxListBox 
  86 bool wxListBox::Create( 
  91 , const wxArrayString
&              asChoices
 
  93 , const wxValidator
&                rValidator
 
  94 , const wxString
&                   rsName
 
  97     wxCArrayString 
chs(asChoices
); 
  99     return Create(pParent
, vId
, rPos
, rSize
, chs
.GetCount(), chs
.GetStrings(), 
 100                   lStyle
, rValidator
, rsName
); 
 103 bool wxListBox::Create( wxWindow
* pParent
, 
 108                         const wxString asChoices
[], 
 110                         const wxValidator
& rValidator
, 
 111                         const wxString
& rsName 
) 
 119     SetValidator(rValidator
); 
 123         pParent
->AddChild(this); 
 125     wxSystemSettings                vSettings
; 
 127     SetBackgroundColour(vSettings
.GetColour(wxSYS_COLOUR_WINDOW
)); 
 128     SetForegroundColour(pParent
->GetForegroundColour()); 
 130     m_windowId 
= (vId 
== -1) ? (int)NewControlId() : vId
; 
 134     int                             nWidth  
= rSize
.x
; 
 135     int                             nHeight 
= rSize
.y
; 
 137     m_windowStyle 
= lStyle
; 
 141     if (m_windowStyle 
& wxCLIP_SIBLINGS 
) 
 142         lStyle 
|= WS_CLIPSIBLINGS
; 
 143     if (m_windowStyle 
& wxLB_MULTIPLE
) 
 144         lStyle 
|= LS_MULTIPLESEL
; 
 145     else if (m_windowStyle 
& wxLB_EXTENDED
) 
 146         lStyle 
|= LS_EXTENDEDSEL
; 
 147     if (m_windowStyle 
& wxLB_HSCROLL
) 
 148         lStyle 
|= LS_HORZSCROLL
; 
 149     if (m_windowStyle 
& wxLB_OWNERDRAW
) 
 150         lStyle 
|= LS_OWNERDRAW
; 
 153     // Without this style, you get unexpected heights, so e.g. constraint layout 
 154     // doesn't work properly 
 156     lStyle 
|= LS_NOADJUSTPOS
; 
 158     m_hWnd 
= (WXHWND
)::WinCreateWindow( GetWinHwnd(pParent
) // Parent 
 159                                        ,WC_LISTBOX          
// Default Listbox class 
 160                                        ,"LISTBOX"           // Control's name 
 161                                        ,lStyle              
// Initial Style 
 162                                        ,0, 0, 0, 0          // Position and size 
 163                                        ,GetWinHwnd(pParent
) // Owner 
 165                                        ,(HMENU
)m_windowId   
// Id 
 166                                        ,NULL                
// Control Data 
 167                                        ,NULL                
// Presentation Parameters 
 175     // Subclass again for purposes of dialog editing mode 
 181     for (lUi 
= 0; lUi 
< (LONG
)n
; lUi
++) 
 183         Append(asChoices
[lUi
]); 
 185     wxFont
*                          pTextFont 
= new wxFont( 10 
 193     // Set OS/2 system colours for Listbox items and highlighting 
 197     vColour 
= wxSystemSettingsNative::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
 199     LONG                            lColor 
= (LONG
)vColour
.GetPixel(); 
 201     ::WinSetPresParam( m_hWnd
 
 202                       ,PP_HILITEFOREGROUNDCOLOR
 
 206     vColour 
= wxSystemSettingsNative::GetColour(wxSYS_COLOUR_HIGHLIGHT
); 
 207     lColor 
= (LONG
)vColour
.GetPixel(); 
 208     ::WinSetPresParam( m_hWnd
 
 209                       ,PP_HILITEBACKGROUNDCOLOR
 
 223 } // end of wxListBox::Create 
 225 wxListBox::~wxListBox() 
 227 #if wxUSE_OWNER_DRAWN 
 228     size_t lUiCount 
= m_aItems
.Count(); 
 230     while (lUiCount
-- != 0) 
 232         delete m_aItems
[lUiCount
]; 
 234 #endif // wxUSE_OWNER_DRAWN 
 235 } // end of wxListBox::~wxListBox 
 237 void wxListBox::SetupColours() 
 239     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 240     SetForegroundColour(GetParent()->GetForegroundColour()); 
 241 } // end of wxListBox::SetupColours 
 243 // ---------------------------------------------------------------------------- 
 244 // implementation of wxListBoxBase methods 
 245 // ---------------------------------------------------------------------------- 
 247 void wxListBox::DoSetFirstItem(int N
) 
 249     wxCHECK_RET( IsValid(N
), 
 250                  wxT("invalid index in wxListBox::SetFirstItem") ); 
 252     ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX
, MPFROMLONG(N
), (MPARAM
)0); 
 253 } // end of wxListBox::DoSetFirstItem 
 255 void wxListBox::DoDeleteOneItem(unsigned int n
) 
 257     wxCHECK_RET( IsValid(n
), 
 258                  wxT("invalid index in wxListBox::Delete") ); 
 260 #if wxUSE_OWNER_DRAWN 
 262     m_aItems
.RemoveAt(n
); 
 263 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN 
 265     ::WinSendMsg(GetHwnd(), LM_DELETEITEM
, (MPARAM
)n
, (MPARAM
)0); 
 267 } // end of wxListBox::DoSetFirstItem 
 269 int wxListBox::DoInsertItems(const wxArrayStringsAdapter 
& items
, 
 272                              wxClientDataType type
) 
 276     bool incrementPos 
= false; 
 279         lIndexType 
= LIT_SORTASCENDING
; 
 280     else if (pos 
== GetCount()) 
 281         lIndexType 
= LIT_END
; 
 284         lIndexType 
= (LONG
)pos
; 
 290     unsigned int count 
= items
.GetCount(); 
 291     for (unsigned int i 
= 0; i 
< count
; i
++) 
 293         n 
= (int)::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)lIndexType
, (MPARAM
)items
[i
].wx_str()); 
 296             wxLogLastError(_T("WinSendMsg(LM_INSERTITEM)")); 
 302 #if wxUSE_OWNER_DRAWN 
 303         if (HasFlag(wxLB_OWNERDRAW
)) 
 305             wxOwnerDrawn
*               pNewItem 
= CreateItem(n
); // dummy argument 
 306             wxScreenDC                  vDc
; // FIXME: is it really needed here? 
 308             pNewItem
->SetName(items
[i
]); 
 309             m_aItems
.Insert(pNewItem
, n
); 
 310             ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, (MPARAM
)n
, MPFROMP(pNewItem
)); 
 311             pNewItem
->SetFont(GetFont()); 
 314         AssignNewItemClientData(n
, clientData
, i
, type
); 
 321 } // end of wxListBox::DoInsertAppendItemsWithData 
 323 void wxListBox::DoClear() 
 325 #if wxUSE_OWNER_DRAWN 
 326     unsigned int lUiCount 
= m_aItems
.Count(); 
 328     while (lUiCount
-- != 0) 
 330         delete m_aItems
[lUiCount
]; 
 334 #endif // wxUSE_OWNER_DRAWN 
 335     ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0); 
 338 } // end of wxListBox::Clear 
 340 void wxListBox::DoSetSelection( int N
, bool bSelect
) 
 342     wxCHECK_RET( IsValid(N
), 
 343                  wxT("invalid index in wxListBox::SetSelection") ); 
 344     ::WinSendMsg( GetHwnd() 
 349     if(m_windowStyle 
& wxLB_OWNERDRAW
) 
 351 } // end of wxListBox::SetSelection 
 353 bool wxListBox::IsSelected( int N 
) const 
 355     wxCHECK_MSG( IsValid(N
), false, 
 356                  wxT("invalid index in wxListBox::Selected") ); 
 360     if (GetWindowStyleFlag() & wxLB_EXTENDED
) 
 363             lItem 
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0)); 
 365             lItem 
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)(N 
- 1), (MPARAM
)0)); 
 369         lItem 
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0)); 
 371     return (lItem 
== (LONG
)N 
&& lItem 
!= LIT_NONE
); 
 372 } // end of wxListBox::IsSelected 
 374 void* wxListBox::DoGetItemClientData(unsigned int n
) const 
 376     wxCHECK_MSG( IsValid(n
), NULL
, 
 377                  wxT("invalid index in wxListBox::GetClientData") ); 
 379     return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE
, MPFROMLONG(n
), (MPARAM
)0)); 
 380 } // end of wxListBox::DoGetItemClientData 
 382 void wxListBox::DoSetItemClientData(unsigned int n
, void* pClientData
) 
 384     wxCHECK_RET( IsValid(n
), 
 385                  wxT("invalid index in wxListBox::SetClientData") ); 
 387 #if wxUSE_OWNER_DRAWN 
 388     if ( m_windowStyle 
& wxLB_OWNERDRAW 
) 
 391         // Client data must be pointer to wxOwnerDrawn, otherwise we would crash 
 392         // in OnMeasure/OnDraw. 
 394         wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes")); 
 396 #endif // wxUSE_OWNER_DRAWN 
 398     ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(n
), MPFROMP(pClientData
)); 
 399 } // end of wxListBox::DoSetItemClientData 
 401 bool wxListBox::HasMultipleSelection() const 
 403     return (m_windowStyle 
& wxLB_MULTIPLE
) || (m_windowStyle 
& wxLB_EXTENDED
); 
 404 } // end of wxListBox::HasMultipleSelection 
 406 int wxListBox::GetSelections( wxArrayInt
& raSelections 
) const 
 412     raSelections
.Empty(); 
 413     if (HasMultipleSelection()) 
 415         lItem 
= LONGFROMMR(::WinSendMsg( GetHwnd() 
 421         if (lItem 
!= LIT_NONE
) 
 424             while ((lItem 
= LONGFROMMR(::WinSendMsg( GetHwnd() 
 433             raSelections
.Alloc(nCount
); 
 434             lItem 
= LONGFROMMR(::WinSendMsg( GetHwnd() 
 441             raSelections
.Add((int)lItem
); 
 442             while ((lItem 
= LONGFROMMR(::WinSendMsg( GetHwnd() 
 449                 raSelections
.Add((int)lItem
); 
 454     else  // single-selection listbox 
 456         lItem 
= LONGFROMMR(::WinSendMsg( GetHwnd() 
 462         raSelections
.Add((int)lItem
); 
 466 } // end of wxListBox::GetSelections 
 468 int wxListBox::GetSelection() const 
 470     wxCHECK_MSG( !HasMultipleSelection(), 
 472                  wxT("GetSelection() can't be used with multiple-selection " 
 473                     "listboxes, use GetSelections() instead.") ); 
 475     return(LONGFROMMR(::WinSendMsg( GetHwnd() 
 481 } // end of wxListBox::GetSelection 
 483 wxString 
wxListBox::GetString(unsigned int n
) const 
 489     wxCHECK_MSG( IsValid(n
), wxEmptyString
, 
 490                  wxT("invalid index in wxListBox::GetClientData") ); 
 492     lLen 
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)n
, (MPARAM
)0)); 
 493     zBuf 
= new wxChar
[lLen 
+ 1]; 
 494     ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT((SHORT
)n
, (SHORT
)lLen
), (MPARAM
)zBuf
); 
 499 } // end of wxListBox::GetString 
 501 void wxListBox::SetString(unsigned int n
, const wxString
& rsString
) 
 503     wxCHECK_RET( IsValid(n
), 
 504                  wxT("invalid index in wxListBox::SetString") ); 
 507     // Remember the state of the item 
 509     bool           bWasSelected 
= IsSelected(n
); 
 510     void*          pOldData 
= NULL
; 
 511     wxClientData
*  pOldObjData 
= NULL
; 
 513     if ( HasClientUntypedData() ) 
 514         pOldData 
= GetClientData(n
); 
 515     else if ( HasClientObjectData() ) 
 516         pOldObjData 
= GetClientObject(n
); 
 519     // Delete and recreate it 
 521     ::WinSendMsg( GetHwnd() 
 529     if (n 
== (m_nNumItems 
- 1)) 
 532     ::WinSendMsg( GetHwnd() 
 535                  ,(MPARAM
)rsString
.wx_str() 
 539     // Restore the client data 
 542         SetClientData(n
, pOldData
); 
 543     else if (pOldObjData
) 
 544         SetClientObject(n
, pOldObjData
); 
 547     // We may have lost the selection 
 552 #if wxUSE_OWNER_DRAWN 
 553     if (m_windowStyle 
& wxLB_OWNERDRAW
) 
 555         // Update item's text 
 557         m_aItems
[n
]->SetName(rsString
); 
 558 #endif  //USE_OWNER_DRAWN 
 559 } // end of wxListBox::SetString 
 561 unsigned int wxListBox::GetCount() const 
 566 // ---------------------------------------------------------------------------- 
 568 // ---------------------------------------------------------------------------- 
 570 wxSize 
wxListBox::DoGetBestSize() const 
 573     // Find the widest string 
 579     wxFont     vFont 
= (wxFont
)GetFont(); 
 581     for (unsigned int i 
= 0; i 
< m_nNumItems
; i
++) 
 583         wxString 
vStr(GetString(i
)); 
 585         GetTextExtent( vStr
, &nLine
, NULL 
); 
 586         if (nLine 
> nListbox
) 
 591     // Give it some reasonable default value if there are no strings in the 
 598     // The listbox should be slightly larger than the widest string 
 600     wxGetCharSize( GetHWND() 
 607     int hListbox 
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy
) * (wxMax(m_nNumItems
, 7)); 
 609     return wxSize( nListbox
 
 612 } // end of wxListBox::DoGetBestSize 
 614 // ---------------------------------------------------------------------------- 
 616 // ---------------------------------------------------------------------------- 
 618 bool wxListBox::OS2Command( 
 620 , WXWORD                            
WXUNUSED(wId
)) 
 622     wxEventType                     eEvtType
; 
 624     if (uParam 
== LN_SELECT
) 
 626         eEvtType 
= wxEVT_COMMAND_LISTBOX_SELECTED
; 
 628     else if (uParam 
== LN_ENTER
) 
 630         eEvtType 
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
; 
 635         // Some event we're not interested in 
 639     wxCommandEvent                  
vEvent( eEvtType
 
 643     vEvent
.SetEventObject(this); 
 645     wxArrayInt aSelections
; 
 647     int        nCount 
= GetSelections(aSelections
); 
 652         if (HasClientObjectData()) 
 653             vEvent
.SetClientObject(GetClientObject(n
)); 
 654         else if ( HasClientUntypedData() ) 
 655             vEvent
.SetClientData(GetClientData(n
)); 
 656         vEvent
.SetString(GetString(n
)); 
 663     return GetEventHandler()->ProcessEvent(vEvent
); 
 664 } // end of wxListBox::OS2Command 
 666 // ---------------------------------------------------------------------------- 
 667 // wxCheckListBox support 
 668 // ---------------------------------------------------------------------------- 
 670 #if wxUSE_OWNER_DRAWN 
 676 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE    (1) 
 678 long wxListBox::OS2OnMeasure(WXMEASUREITEMSTRUCT
* pItem
) 
 681         pItem 
= (WXMEASUREITEMSTRUCT
*)new OWNERITEM
; 
 683     POWNERITEM                      pMeasureStruct 
= (POWNERITEM
)pItem
; 
 687     // Only owner-drawn control should receive this message 
 689     wxCHECK( ((m_windowStyle 
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE 
); 
 691     vDc
.SetFont(GetFont()); 
 700     pMeasureStruct
->rclItem
.xRight 
= (USHORT
)vWidth
; 
 701     pMeasureStruct
->rclItem
.xLeft  
= 0; 
 702     pMeasureStruct
->rclItem
.yTop   
= 0; 
 703     pMeasureStruct
->rclItem
.yBottom 
= 0; 
 705     vHeight 
= (wxCoord
)(vDc
.GetCharHeight() * 2.5); 
 706     pMeasureStruct
->rclItem
.yTop  
= (USHORT
)vHeight
; 
 708     return long(MRFROM2SHORT((USHORT
)vHeight
, (USHORT
)vWidth
)); 
 709 } // end of wxListBox::OS2OnMeasure 
 711 bool wxListBox::OS2OnDraw ( 
 712   WXDRAWITEMSTRUCT
*                 pItem
 
 715     POWNERITEM                      pDrawStruct 
= (POWNERITEM
)pItem
; 
 716     LONG                            lItemID 
= pDrawStruct
->idItem
; 
 721     // Only owner-drawn control should receive this message 
 723     wxCHECK(((m_windowStyle 
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), false); 
 727     // The item may be -1 for an empty listbox 
 732     wxListBoxItem
*                   pData 
= (wxListBoxItem
*)PVOIDFROMMR( ::WinSendMsg( GetHwnd() 
 734                                                                                        ,MPFROMLONG(pDrawStruct
->idItem
) 
 739     wxCHECK(pData
, false ); 
 742     wxPoint 
pt1( pDrawStruct
->rclItem
.xLeft
, pDrawStruct
->rclItem
.yTop 
); 
 743     wxPoint 
pt2( pDrawStruct
->rclItem
.xRight
, pDrawStruct
->rclItem
.yBottom 
); 
 744     wxRect  
vRect( pt1
, pt2 
); 
 746     vDc
.SetHPS(pDrawStruct
->hps
); 
 748     if (pDrawStruct
->fsAttribute 
== pDrawStruct
->fsAttributeOld
) 
 751         // Entire Item needs to be redrawn (either it has reappeared from 
 752         // behind another window or is being displayed for the first time 
 754         eAction 
= wxOwnerDrawn::wxODDrawAll
; 
 756         if (pDrawStruct
->fsAttribute 
& MIA_HILITED
) 
 759             // If it is currently selected we let the system handle it 
 761             eStatus 
|= wxOwnerDrawn::wxODSelected
; 
 763         if (pDrawStruct
->fsAttribute 
& MIA_CHECKED
) 
 766             // If it is currently checked we draw our own 
 768             eStatus 
|= wxOwnerDrawn::wxODChecked
; 
 769             pDrawStruct
->fsAttributeOld 
= pDrawStruct
->fsAttribute 
&= ~MIA_CHECKED
; 
 771         if (pDrawStruct
->fsAttribute 
& MIA_DISABLED
) 
 774             // If it is currently disabled we let the system handle it 
 776             eStatus 
|= wxOwnerDrawn::wxODDisabled
; 
 779         // Don't really care about framed (indicationg focus) or NoDismiss 
 784         if (pDrawStruct
->fsAttribute 
& MIA_HILITED
) 
 786             eAction 
= wxOwnerDrawn::wxODDrawAll
; 
 787             eStatus 
|= wxOwnerDrawn::wxODSelected
; 
 789             // Keep the system from trying to highlight with its bogus colors 
 791             pDrawStruct
->fsAttributeOld 
= pDrawStruct
->fsAttribute 
&= ~MIA_HILITED
; 
 793         else if (!(pDrawStruct
->fsAttribute 
& MIA_HILITED
)) 
 795             eAction 
= wxOwnerDrawn::wxODDrawAll
; 
 798             // Keep the system from trying to highlight with its bogus colors 
 800             pDrawStruct
->fsAttribute 
= pDrawStruct
->fsAttributeOld 
&= ~MIA_HILITED
; 
 805             // For now we don't care about anything else 
 806             // just ignore the entire message! 
 811     return pData
->OnDrawItem( vDc
 
 813                              ,(wxOwnerDrawn::wxODAction
)eAction
 
 814                              ,(wxOwnerDrawn::wxODStatus
)eStatus
 
 816 } // end of wxListBox::OS2OnDraw 
 818 #endif // ndef for wxUSE_OWNER_DRAWN 
 820 #endif // wxUSE_LISTBOX