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/dcclient.h" 
  33 #include "wx/os2/private.h" 
  39     #include  "wx/ownerdrw.h" 
  42 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControlWithItems
) 
  44 // ============================================================================ 
  45 // list box item declaration and implementation 
  46 // ============================================================================ 
  50 class wxListBoxItem 
: public wxOwnerDrawn
 
  53     wxListBoxItem(const wxString
& rsStr 
= wxEmptyString
); 
  56 wxListBoxItem::wxListBoxItem( 
  64     // No bitmaps/checkmarks 
  67 } // end of wxListBoxItem::wxListBoxItem 
  69 wxOwnerDrawn
* wxListBox::CreateItem( size_t WXUNUSED(n
) ) 
  71     return new wxListBoxItem(); 
  72 } // end of wxListBox::CreateItem 
  74 #endif  //USE_OWNER_DRAWN 
  76 // ============================================================================ 
  77 // list box control implementation 
  78 // ============================================================================ 
  81 wxListBox::wxListBox() 
  85 } // end of wxListBox::wxListBox 
  87 bool wxListBox::Create( 
  92 , const wxArrayString
&              asChoices
 
  94 , const wxValidator
&                rValidator
 
  95 , const wxString
&                   rsName
 
  98     wxCArrayString 
chs(asChoices
); 
 100     return Create(pParent
, vId
, rPos
, rSize
, chs
.GetCount(), chs
.GetStrings(), 
 101                   lStyle
, rValidator
, rsName
); 
 104 bool wxListBox::Create( wxWindow
* pParent
, 
 109                         const wxString asChoices
[], 
 111                         const wxValidator
& rValidator
, 
 112                         const wxString
& rsName 
) 
 120     SetValidator(rValidator
); 
 124         pParent
->AddChild(this); 
 126     wxSystemSettings                vSettings
; 
 128     SetBackgroundColour(vSettings
.GetColour(wxSYS_COLOUR_WINDOW
)); 
 129     SetForegroundColour(pParent
->GetForegroundColour()); 
 131     m_windowId 
= (vId 
== -1) ? (int)NewControlId() : vId
; 
 135     int                             nWidth  
= rSize
.x
; 
 136     int                             nHeight 
= rSize
.y
; 
 138     m_windowStyle 
= lStyle
; 
 142     if (m_windowStyle 
& wxCLIP_SIBLINGS 
) 
 143         lStyle 
|= WS_CLIPSIBLINGS
; 
 144     if (m_windowStyle 
& wxLB_MULTIPLE
) 
 145         lStyle 
|= LS_MULTIPLESEL
; 
 146     else if (m_windowStyle 
& wxLB_EXTENDED
) 
 147         lStyle 
|= LS_EXTENDEDSEL
; 
 148     if (m_windowStyle 
& wxLB_HSCROLL
) 
 149         lStyle 
|= LS_HORZSCROLL
; 
 150     if (m_windowStyle 
& wxLB_OWNERDRAW
) 
 151         lStyle 
|= LS_OWNERDRAW
; 
 154     // Without this style, you get unexpected heights, so e.g. constraint layout 
 155     // doesn't work properly 
 157     lStyle 
|= LS_NOADJUSTPOS
; 
 159     m_hWnd 
= (WXHWND
)::WinCreateWindow( GetWinHwnd(pParent
) // Parent 
 160                                        ,WC_LISTBOX          
// Default Listbox class 
 161                                        ,"LISTBOX"           // Control's name 
 162                                        ,lStyle              
// Initial Style 
 163                                        ,0, 0, 0, 0          // Position and size 
 164                                        ,GetWinHwnd(pParent
) // Owner 
 166                                        ,(HMENU
)m_windowId   
// Id 
 167                                        ,NULL                
// Control Data 
 168                                        ,NULL                
// Presentation Parameters 
 176     // Subclass again for purposes of dialog editing mode 
 182     for (lUi 
= 0; lUi 
< (LONG
)n
; lUi
++) 
 184         Append(asChoices
[lUi
]); 
 186     wxFont
*                          pTextFont 
= new wxFont( 10 
 194     // Set OS/2 system colours for Listbox items and highlighting 
 198     vColour 
= wxSystemSettingsNative::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
 200     LONG                            lColor 
= (LONG
)vColour
.GetPixel(); 
 202     ::WinSetPresParam( m_hWnd
 
 203                       ,PP_HILITEFOREGROUNDCOLOR
 
 207     vColour 
= wxSystemSettingsNative::GetColour(wxSYS_COLOUR_HIGHLIGHT
); 
 208     lColor 
= (LONG
)vColour
.GetPixel(); 
 209     ::WinSetPresParam( m_hWnd
 
 210                       ,PP_HILITEBACKGROUNDCOLOR
 
 224 } // end of wxListBox::Create 
 226 wxListBox::~wxListBox() 
 228 #if wxUSE_OWNER_DRAWN 
 229     size_t lUiCount 
= m_aItems
.Count(); 
 231     while (lUiCount
-- != 0) 
 233         delete m_aItems
[lUiCount
]; 
 235 #endif // wxUSE_OWNER_DRAWN 
 236 } // end of wxListBox::~wxListBox 
 238 void wxListBox::SetupColours() 
 240     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
 241     SetForegroundColour(GetParent()->GetForegroundColour()); 
 242 } // end of wxListBox::SetupColours 
 244 // ---------------------------------------------------------------------------- 
 245 // implementation of wxListBoxBase methods 
 246 // ---------------------------------------------------------------------------- 
 248 void wxListBox::DoSetFirstItem(int N
) 
 250     wxCHECK_RET( IsValid(N
), 
 251                  wxT("invalid index in wxListBox::SetFirstItem") ); 
 253     ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX
, MPFROMLONG(N
), (MPARAM
)0); 
 254 } // end of wxListBox::DoSetFirstItem 
 256 void wxListBox::DoDeleteOneItem(unsigned int n
) 
 258     wxCHECK_RET( IsValid(n
), 
 259                  wxT("invalid index in wxListBox::Delete") ); 
 261 #if wxUSE_OWNER_DRAWN 
 263     m_aItems
.RemoveAt(n
); 
 264 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN 
 266     ::WinSendMsg(GetHwnd(), LM_DELETEITEM
, (MPARAM
)n
, (MPARAM
)0); 
 268 } // end of wxListBox::DoSetFirstItem 
 270 int wxListBox::DoInsertItems(const wxArrayStringsAdapter 
& items
, 
 273                              wxClientDataType type
) 
 277     bool incrementPos 
= false; 
 280         lIndexType 
= LIT_SORTASCENDING
; 
 281     else if (pos 
== GetCount()) 
 282         lIndexType 
= LIT_END
; 
 285         lIndexType 
= (LONG
)pos
; 
 291     unsigned int count 
= items
.GetCount(); 
 292     for (unsigned int i 
= 0; i 
< count
; i
++) 
 294         n 
= (int)::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)lIndexType
, (MPARAM
)items
[i
].wx_str()); 
 297             wxLogLastError(_T("WinSendMsg(LM_INSERTITEM)")); 
 303 #if wxUSE_OWNER_DRAWN 
 304         if (HasFlag(wxLB_OWNERDRAW
)) 
 306             wxOwnerDrawn
*               pNewItem 
= CreateItem(n
); // dummy argument 
 307             wxScreenDC                  vDc
; // FIXME: is it really needed here? 
 309             pNewItem
->SetName(items
[i
]); 
 310             m_aItems
.Insert(pNewItem
, n
); 
 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     ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(n
), MPFROMP(pClientData
)); 
 388 } // end of wxListBox::DoSetItemClientData 
 390 bool wxListBox::HasMultipleSelection() const 
 392     return (m_windowStyle 
& wxLB_MULTIPLE
) || (m_windowStyle 
& wxLB_EXTENDED
); 
 393 } // end of wxListBox::HasMultipleSelection 
 395 int wxListBox::GetSelections( wxArrayInt
& raSelections 
) const 
 401     raSelections
.Empty(); 
 402     if (HasMultipleSelection()) 
 404         lItem 
= LONGFROMMR(::WinSendMsg( GetHwnd() 
 410         if (lItem 
!= LIT_NONE
) 
 413             while ((lItem 
= LONGFROMMR(::WinSendMsg( GetHwnd() 
 422             raSelections
.Alloc(nCount
); 
 423             lItem 
= LONGFROMMR(::WinSendMsg( GetHwnd() 
 430             raSelections
.Add((int)lItem
); 
 431             while ((lItem 
= LONGFROMMR(::WinSendMsg( GetHwnd() 
 438                 raSelections
.Add((int)lItem
); 
 443     else  // single-selection listbox 
 445         lItem 
= LONGFROMMR(::WinSendMsg( GetHwnd() 
 451         raSelections
.Add((int)lItem
); 
 455 } // end of wxListBox::GetSelections 
 457 int wxListBox::GetSelection() const 
 459     wxCHECK_MSG( !HasMultipleSelection(), 
 461                  wxT("GetSelection() can't be used with multiple-selection " 
 462                     "listboxes, use GetSelections() instead.") ); 
 464     return(LONGFROMMR(::WinSendMsg( GetHwnd() 
 470 } // end of wxListBox::GetSelection 
 472 wxString 
wxListBox::GetString(unsigned int n
) const 
 478     wxCHECK_MSG( IsValid(n
), wxEmptyString
, 
 479                  wxT("invalid index in wxListBox::GetClientData") ); 
 481     lLen 
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)n
, (MPARAM
)0)); 
 482     zBuf 
= new wxChar
[lLen 
+ 1]; 
 483     ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT((SHORT
)n
, (SHORT
)lLen
), (MPARAM
)zBuf
); 
 488 } // end of wxListBox::GetString 
 490 void wxListBox::SetString(unsigned int n
, const wxString
& rsString
) 
 492     wxCHECK_RET( IsValid(n
), 
 493                  wxT("invalid index in wxListBox::SetString") ); 
 496     // Remember the state of the item 
 498     bool           bWasSelected 
= IsSelected(n
); 
 499     void*          pOldData 
= NULL
; 
 500     wxClientData
*  pOldObjData 
= NULL
; 
 502     if ( HasClientUntypedData() ) 
 503         pOldData 
= GetClientData(n
); 
 504     else if ( HasClientObjectData() ) 
 505         pOldObjData 
= GetClientObject(n
); 
 508     // Delete and recreate it 
 510     ::WinSendMsg( GetHwnd() 
 518     if (n 
== (m_nNumItems 
- 1)) 
 521     ::WinSendMsg( GetHwnd() 
 524                  ,(MPARAM
)rsString
.wx_str() 
 528     // Restore the client data 
 531         SetClientData(n
, pOldData
); 
 532     else if (pOldObjData
) 
 533         SetClientObject(n
, pOldObjData
); 
 536     // We may have lost the selection 
 541 #if wxUSE_OWNER_DRAWN 
 542     if (m_windowStyle 
& wxLB_OWNERDRAW
) 
 544         // Update item's text 
 546         m_aItems
[n
]->SetName(rsString
); 
 547 #endif  //USE_OWNER_DRAWN 
 548 } // end of wxListBox::SetString 
 550 unsigned int wxListBox::GetCount() const 
 555 // ---------------------------------------------------------------------------- 
 557 // ---------------------------------------------------------------------------- 
 559 wxSize 
wxListBox::DoGetBestSize() const 
 562     // Find the widest string 
 568     wxFont     vFont 
= (wxFont
)GetFont(); 
 570     for (unsigned int i 
= 0; i 
< m_nNumItems
; i
++) 
 572         wxString 
vStr(GetString(i
)); 
 574         GetTextExtent( vStr
, &nLine
, NULL 
); 
 575         if (nLine 
> nListbox
) 
 580     // Give it some reasonable default value if there are no strings in the 
 587     // The listbox should be slightly larger than the widest string 
 589     wxGetCharSize( GetHWND() 
 596     int hListbox 
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy
) * (wxMax(m_nNumItems
, 7)); 
 598     return wxSize( nListbox
 
 601 } // end of wxListBox::DoGetBestSize 
 603 // ---------------------------------------------------------------------------- 
 605 // ---------------------------------------------------------------------------- 
 607 bool wxListBox::OS2Command( 
 609 , WXWORD                            
WXUNUSED(wId
)) 
 611     wxEventType                     eEvtType
; 
 613     if (uParam 
== LN_SELECT
) 
 615         eEvtType 
= wxEVT_COMMAND_LISTBOX_SELECTED
; 
 617     else if (uParam 
== LN_ENTER
) 
 619         eEvtType 
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
; 
 624         // Some event we're not interested in 
 628     wxCommandEvent                  
vEvent( eEvtType
 
 632     vEvent
.SetEventObject(this); 
 634     wxArrayInt aSelections
; 
 636     int        nCount 
= GetSelections(aSelections
); 
 641         if (HasClientObjectData()) 
 642             vEvent
.SetClientObject(GetClientObject(n
)); 
 643         else if ( HasClientUntypedData() ) 
 644             vEvent
.SetClientData(GetClientData(n
)); 
 645         vEvent
.SetString(GetString(n
)); 
 652     return HandleWindowEvent(vEvent
); 
 653 } // end of wxListBox::OS2Command 
 655 // ---------------------------------------------------------------------------- 
 656 // wxCheckListBox support 
 657 // ---------------------------------------------------------------------------- 
 659 #if wxUSE_OWNER_DRAWN 
 665 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE    (1) 
 667 long wxListBox::OS2OnMeasure(WXMEASUREITEMSTRUCT
* pItem
) 
 670         pItem 
= (WXMEASUREITEMSTRUCT
*)new OWNERITEM
; 
 672     POWNERITEM                      pMeasureStruct 
= (POWNERITEM
)pItem
; 
 676     // Only owner-drawn control should receive this message 
 678     wxCHECK( ((m_windowStyle 
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE 
); 
 680     vDc
.SetFont(GetFont()); 
 689     pMeasureStruct
->rclItem
.xRight 
= (USHORT
)vWidth
; 
 690     pMeasureStruct
->rclItem
.xLeft  
= 0; 
 691     pMeasureStruct
->rclItem
.yTop   
= 0; 
 692     pMeasureStruct
->rclItem
.yBottom 
= 0; 
 694     vHeight 
= (wxCoord
)(vDc
.GetCharHeight() * 2.5); 
 695     pMeasureStruct
->rclItem
.yTop  
= (USHORT
)vHeight
; 
 697     return long(MRFROM2SHORT((USHORT
)vHeight
, (USHORT
)vWidth
)); 
 698 } // end of wxListBox::OS2OnMeasure 
 700 bool wxListBox::OS2OnDraw ( 
 701   WXDRAWITEMSTRUCT
*                 pItem
 
 704     POWNERITEM                      pDrawStruct 
= (POWNERITEM
)pItem
; 
 709     // Only owner-drawn control should receive this message 
 711     wxCHECK(((m_windowStyle 
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), false); 
 715     // The item may be -1 for an empty listbox 
 717     if (pDrawStruct
->idItem 
== -1L) 
 720     wxListBoxItem
* pData 
= (wxListBoxItem
*)m_aItems
[pDrawStruct
->idItem
]; 
 722     wxClientDC    
vDc(this); 
 723     wxPMDCImpl 
*impl 
= (wxPMDCImpl
*) vDc
.GetImpl(); 
 724     wxPoint 
pt1( pDrawStruct
->rclItem
.xLeft
, pDrawStruct
->rclItem
.yTop 
); 
 725     wxPoint 
pt2( pDrawStruct
->rclItem
.xRight
, pDrawStruct
->rclItem
.yBottom 
); 
 726     wxRect  
vRect( pt1
, pt2 
); 
 728     impl
->SetHPS(pDrawStruct
->hps
); 
 730     if (pDrawStruct
->fsAttribute 
== pDrawStruct
->fsAttributeOld
) 
 733         // Entire Item needs to be redrawn (either it has reappeared from 
 734         // behind another window or is being displayed for the first time 
 736         eAction 
= wxOwnerDrawn::wxODDrawAll
; 
 738         if (pDrawStruct
->fsAttribute 
& MIA_HILITED
) 
 741             // If it is currently selected we let the system handle it 
 743             eStatus 
|= wxOwnerDrawn::wxODSelected
; 
 745         if (pDrawStruct
->fsAttribute 
& MIA_CHECKED
) 
 748             // If it is currently checked we draw our own 
 750             eStatus 
|= wxOwnerDrawn::wxODChecked
; 
 751             pDrawStruct
->fsAttributeOld 
= pDrawStruct
->fsAttribute 
&= ~MIA_CHECKED
; 
 753         if (pDrawStruct
->fsAttribute 
& MIA_DISABLED
) 
 756             // If it is currently disabled we let the system handle it 
 758             eStatus 
|= wxOwnerDrawn::wxODDisabled
; 
 761         // Don't really care about framed (indicationg focus) or NoDismiss 
 766         if (pDrawStruct
->fsAttribute 
& MIA_HILITED
) 
 768             eAction 
= wxOwnerDrawn::wxODDrawAll
; 
 769             eStatus 
|= wxOwnerDrawn::wxODSelected
; 
 771             // Keep the system from trying to highlight with its bogus colors 
 773             pDrawStruct
->fsAttributeOld 
= pDrawStruct
->fsAttribute 
&= ~MIA_HILITED
; 
 775         else if (!(pDrawStruct
->fsAttribute 
& MIA_HILITED
)) 
 777             eAction 
= wxOwnerDrawn::wxODDrawAll
; 
 780             // Keep the system from trying to highlight with its bogus colors 
 782             pDrawStruct
->fsAttribute 
= pDrawStruct
->fsAttributeOld 
&= ~MIA_HILITED
; 
 787             // For now we don't care about anything else 
 788             // just ignore the entire message! 
 793     return pData
->OnDrawItem( vDc
 
 795                              ,(wxOwnerDrawn::wxODAction
)eAction
 
 796                              ,(wxOwnerDrawn::wxODStatus
)eStatus
 
 798 } // end of wxListBox::OS2OnDraw 
 800 #endif // ndef for wxUSE_OWNER_DRAWN 
 802 #endif // wxUSE_LISTBOX