1 ///////////////////////////////////////////////////////////////////////////////
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"
15 #include "wx/window.h"
16 #include "wx/os2/private.h"
19 #include "wx/listbox.h"
20 #include "wx/settings.h"
24 #include "wx/dcscreen.h"
26 #include "wx/scrolwin.h"
32 #include "wx/dynarray.h"
38 #include "wx/ownerdrw.h"
41 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControl
)
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(
106 , const wxPoint
& rPos
107 , const wxSize
& rSize
109 , const wxString asChoices
[]
111 , const wxValidator
& rValidator
112 , const wxString
& rsName
121 SetValidator(rValidator
);
125 pParent
->AddChild(this);
127 wxSystemSettings vSettings
;
129 SetBackgroundColour(vSettings
.GetColour(wxSYS_COLOUR_WINDOW
));
130 SetForegroundColour(pParent
->GetForegroundColour());
132 m_windowId
= (vId
== -1) ? (int)NewControlId() : vId
;
136 int nWidth
= rSize
.x
;
137 int nHeight
= rSize
.y
;
139 m_windowStyle
= lStyle
;
143 if (m_windowStyle
& wxCLIP_SIBLINGS
)
144 lStyle
|= WS_CLIPSIBLINGS
;
145 if (m_windowStyle
& wxLB_MULTIPLE
)
146 lStyle
|= LS_MULTIPLESEL
;
147 else if (m_windowStyle
& wxLB_EXTENDED
)
148 lStyle
|= LS_EXTENDEDSEL
;
149 if (m_windowStyle
& wxLB_HSCROLL
)
150 lStyle
|= LS_HORZSCROLL
;
151 if (m_windowStyle
& wxLB_OWNERDRAW
)
152 lStyle
|= LS_OWNERDRAW
;
155 // Without this style, you get unexpected heights, so e.g. constraint layout
156 // doesn't work properly
158 lStyle
|= LS_NOADJUSTPOS
;
160 m_hWnd
= (WXHWND
)::WinCreateWindow( GetWinHwnd(pParent
) // Parent
161 ,WC_LISTBOX
// Default Listbox class
162 ,"LISTBOX" // Control's name
163 ,lStyle
// Initial Style
164 ,0, 0, 0, 0 // Position and size
165 ,GetWinHwnd(pParent
) // Owner
167 ,(HMENU
)m_windowId
// Id
168 ,NULL
// Control Data
169 ,NULL
// Presentation Parameters
177 // Subclass again for purposes of dialog editing mode
183 for (lUi
= 0; lUi
< (LONG
)n
; lUi
++)
185 Append(asChoices
[lUi
]);
187 wxFont
* pTextFont
= new wxFont( 10
195 // Set standard wxWidgets colors for Listbox items and highlighting
199 vColour
.Set(wxString(wxT("WHITE")));
201 LONG lColor
= (LONG
)vColour
.GetPixel();
203 ::WinSetPresParam( m_hWnd
204 ,PP_HILITEFOREGROUNDCOLOR
208 vColour
.Set(wxString(wxT("NAVY")));
209 lColor
= (LONG
)vColour
.GetPixel();
210 ::WinSetPresParam( m_hWnd
211 ,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(
251 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
252 wxT("invalid index in wxListBox::SetFirstItem") );
254 ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX
, MPFROMLONG(N
), (MPARAM
)0);
255 } // end of wxListBox::DoSetFirstItem
257 void wxListBox::Delete(
261 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
262 wxT("invalid index in wxListBox::Delete") );
264 #if wxUSE_OWNER_DRAWN
266 m_aItems
.RemoveAt(N
);
267 #else // !wxUSE_OWNER_DRAWN
268 if (HasClientObjectData())
270 delete GetClientObject(N
);
272 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
274 ::WinSendMsg(GetHwnd(), LM_DELETEITEM
, (MPARAM
)N
, (MPARAM
)0);
276 } // end of wxListBox::DoSetFirstItem
278 int wxListBox::DoAppend(
279 const wxString
& rsItem
285 if (m_windowStyle
& wxLB_SORT
)
286 lIndexType
= LIT_SORTASCENDING
;
288 lIndexType
= LIT_END
;
289 lIndex
= (long)::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)lIndexType
, (MPARAM
)rsItem
.c_str());
292 #if wxUSE_OWNER_DRAWN
293 if (m_windowStyle
& wxLB_OWNERDRAW
)
295 wxOwnerDrawn
* pNewItem
= CreateItem(lIndex
); // dummy argument
299 pNewItem
->SetName(rsItem
);
300 m_aItems
.Insert(pNewItem
, lIndex
);
301 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, (MPARAM
)lIndex
, MPFROMP(pNewItem
));
302 pNewItem
->SetFont(GetFont());
306 } // end of wxListBox::DoAppend
308 void wxListBox::DoSetItems(
309 const wxArrayString
& raChoices
310 , void** ppClientData
313 BOOL bHideAndShow
= IsShown();
319 ::WinShowWindow(GetHwnd(), FALSE
);
321 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
322 m_nNumItems
= raChoices
.GetCount();
323 for (i
= 0; i
< m_nNumItems
; i
++)
326 if (m_windowStyle
& wxLB_SORT
)
327 lIndexType
= LIT_SORTASCENDING
;
329 lIndexType
= LIT_END
;
330 ::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)lIndexType
, (MPARAM
)raChoices
[i
].c_str());
334 #if wxUSE_OWNER_DRAWN
335 wxASSERT_MSG(ppClientData
[i
] == NULL
,
336 wxT("Can't use client data with owner-drawn listboxes"));
337 #else // !wxUSE_OWNER_DRAWN
338 ::WinSendMsg(WinUtil_GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(lCount
), MPFROMP(ppClientData
[i
]));
339 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
343 #if wxUSE_OWNER_DRAWN
344 if ( m_windowStyle
& wxLB_OWNERDRAW
)
347 // First delete old items
349 WX_CLEAR_ARRAY(m_aItems
);
352 // Then create new ones
354 for (size_t ui
= 0; ui
< (size_t)m_nNumItems
; ui
++)
356 wxOwnerDrawn
* pNewItem
= CreateItem(ui
);
358 pNewItem
->SetName(raChoices
[ui
]);
359 m_aItems
.Add(pNewItem
);
360 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(ui
), MPFROMP(pNewItem
));
363 #endif // wxUSE_OWNER_DRAWN
364 ::WinShowWindow(GetHwnd(), TRUE
);
365 } // end of wxListBox::DoSetItems
367 int wxListBox::FindString(
368 const wxString
& rsString
376 for (nPos
= 0; nPos
< m_nNumItems
; nPos
++)
378 lTextLength
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)nPos
, (MPARAM
)0));
379 zStr
= new char[lTextLength
+ 1];
380 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT(nPos
, (SHORT
)lTextLength
), (MPARAM
)zStr
);
381 if (rsString
== (wxChar
*)zStr
)
389 } // end of wxListBox::FindString
391 void wxListBox::Clear()
393 #if wxUSE_OWNER_DRAWN
394 size_t lUiCount
= m_aItems
.Count();
396 while (lUiCount
-- != 0)
398 delete m_aItems
[lUiCount
];
402 #else // !wxUSE_OWNER_DRAWN
403 if (HasClientObjectData())
405 for (size_t n
= 0; n
< (size_t)m_lNumItems
; n
++)
407 delete GetClientObject(n
);
410 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
411 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
414 } // end of wxListBox::Clear
416 void wxListBox::DoSetSelection(
421 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
422 wxT("invalid index in wxListBox::SetSelection") );
423 ::WinSendMsg( GetHwnd()
428 if(m_windowStyle
& wxLB_OWNERDRAW
)
430 } // end of wxListBox::SetSelection
432 bool wxListBox::IsSelected(
436 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, false,
437 wxT("invalid index in wxListBox::Selected") );
441 if (GetWindowStyleFlag() & wxLB_EXTENDED
)
444 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
446 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)(N
- 1), (MPARAM
)0));
450 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
452 return (lItem
== (LONG
)N
&& lItem
!= LIT_NONE
);
453 } // end of wxListBox::IsSelected
455 wxClientData
* wxListBox::DoGetItemClientObject(
459 return (wxClientData
*)DoGetItemClientData(n
);
462 void* wxListBox::DoGetItemClientData(
466 wxCHECK_MSG( n
>= 0 && n
< m_nNumItems
, NULL
,
467 wxT("invalid index in wxListBox::GetClientData") );
469 return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE
, MPFROMLONG(n
), (MPARAM
)0));
470 } // end of wxListBox::DoGetItemClientData
472 void wxListBox::DoSetItemClientObject(
474 , wxClientData
* pClientData
477 DoSetItemClientData( n
480 } // end of wxListBox::DoSetItemClientObject
482 void wxListBox::DoSetItemClientData(
487 wxCHECK_RET( n
>= 0 && n
< m_nNumItems
,
488 wxT("invalid index in wxListBox::SetClientData") );
490 #if wxUSE_OWNER_DRAWN
491 if ( m_windowStyle
& wxLB_OWNERDRAW
)
494 // Client data must be pointer to wxOwnerDrawn, otherwise we would crash
495 // in OnMeasure/OnDraw.
497 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
499 #endif // wxUSE_OWNER_DRAWN
501 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(n
), MPFROMP(pClientData
));
502 } // end of wxListBox::DoSetItemClientData
504 bool wxListBox::HasMultipleSelection() const
506 return (m_windowStyle
& wxLB_MULTIPLE
) || (m_windowStyle
& wxLB_EXTENDED
);
507 } // end of wxListBox::HasMultipleSelection
509 int wxListBox::GetSelections( wxArrayInt
& raSelections
) const
515 raSelections
.Empty();
516 if (HasMultipleSelection())
518 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
524 if (lItem
!= LIT_NONE
)
527 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
536 raSelections
.Alloc(nCount
);
537 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
544 raSelections
.Add((int)lItem
);
545 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
552 raSelections
.Add((int)lItem
);
557 else // single-selection listbox
559 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
565 raSelections
.Add((int)lItem
);
569 } // end of wxListBox::GetSelections
571 int wxListBox::GetSelection() const
573 wxCHECK_MSG( !HasMultipleSelection(),
575 wxT("GetSelection() can't be used with multiple-selection "
576 "listboxes, use GetSelections() instead.") );
578 return(LONGFROMMR(::WinSendMsg( GetHwnd()
584 } // end of wxListBox::GetSelection
586 wxString
wxListBox::GetString(
594 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, wxEmptyString
,
595 wxT("invalid index in wxListBox::GetClientData") );
597 lLen
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)N
, (MPARAM
)0));
598 zBuf
= new wxChar
[lLen
+ 1];
599 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT((SHORT
)N
, (SHORT
)lLen
), (MPARAM
)zBuf
);
604 } // end of wxListBox::GetString
606 void wxListBox::DoInsertItems(
607 const wxArrayString
& asItems
611 wxCHECK_RET( nPos
>= 0 && nPos
<= m_nNumItems
,
612 wxT("invalid index in wxListBox::InsertItems") );
614 int nItems
= asItems
.GetCount();
616 for (int i
= 0; i
< nItems
; i
++)
618 int nIndex
= (int)::WinSendMsg( GetHwnd()
620 ,MPFROMLONG((LONG
)(i
+ nPos
))
621 ,(MPARAM
)asItems
[i
].c_str()
624 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
);
626 pNewItem
->SetName(asItems
[i
]);
627 pNewItem
->SetFont(GetFont());
628 m_aItems
.Insert(pNewItem
, nIndex
);
629 ::WinSendMsg( GetHwnd()
631 ,(MPARAM
)((LONG
)nIndex
)
634 m_nNumItems
+= nItems
;
636 } // end of wxListBox::DoInsertItems
638 void wxListBox::SetString(
640 , const wxString
& rsString
643 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
644 wxT("invalid index in wxListBox::SetString") );
647 // Remember the state of the item
649 bool bWasSelected
= IsSelected(N
);
650 void* pOldData
= NULL
;
651 wxClientData
* pOldObjData
= NULL
;
653 if (m_clientDataItemsType
== wxClientData_Void
)
654 pOldData
= GetClientData(N
);
655 else if (m_clientDataItemsType
== wxClientData_Object
)
656 pOldObjData
= GetClientObject(N
);
659 // Delete and recreate it
661 ::WinSendMsg( GetHwnd()
669 if (N
== m_nNumItems
- 1)
672 ::WinSendMsg( GetHwnd()
675 ,(MPARAM
)rsString
.c_str()
679 // Restore the client data
685 else if (pOldObjData
)
691 // We may have lost the selection
696 #if wxUSE_OWNER_DRAWN
697 if (m_windowStyle
& wxLB_OWNERDRAW
)
699 // Update item's text
701 m_aItems
[N
]->SetName(rsString
);
702 #endif //USE_OWNER_DRAWN
703 } // end of wxListBox::SetString
705 int wxListBox::GetCount() const
710 // ----------------------------------------------------------------------------
712 // ----------------------------------------------------------------------------
714 wxSize
wxListBox::DoGetBestSize() const
717 // Find the widest string
723 wxFont vFont
= (wxFont
)GetFont();
725 for (int i
= 0; i
< m_nNumItems
; i
++)
727 wxString
vStr(GetString(i
));
733 if (nLine
> nListbox
)
738 // Give it some reasonable default value if there are no strings in the
745 // The listbox should be slightly larger than the widest string
747 wxGetCharSize( GetHWND()
754 int hListbox
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy
) * (wxMax(m_nNumItems
, 7));
756 return wxSize( nListbox
759 } // end of wxListBox::DoGetBestSize
761 // ----------------------------------------------------------------------------
763 // ----------------------------------------------------------------------------
765 bool wxListBox::OS2Command(
767 , WXWORD
WXUNUSED(wId
))
769 wxEventType eEvtType
;
771 if (uParam
== LN_SELECT
)
773 eEvtType
= wxEVT_COMMAND_LISTBOX_SELECTED
;
775 if (uParam
== LN_ENTER
)
777 eEvtType
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
;
782 // Some event we're not interested in
786 wxCommandEvent
vEvent( eEvtType
790 vEvent
.SetEventObject(this);
792 wxArrayInt aSelections
;
794 int nCount
= GetSelections(aSelections
);
799 if (HasClientObjectData())
800 vEvent
.SetClientObject(GetClientObject(n
));
801 else if ( HasClientUntypedData() )
802 vEvent
.SetClientData(GetClientData(n
));
803 vEvent
.SetString(GetString(n
));
810 return GetEventHandler()->ProcessEvent(vEvent
);
811 } // end of wxListBox::OS2Command
813 // ----------------------------------------------------------------------------
814 // wxCheckListBox support
815 // ----------------------------------------------------------------------------
817 #if wxUSE_OWNER_DRAWN
823 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
825 long wxListBox::OS2OnMeasure(
826 WXMEASUREITEMSTRUCT
* pItem
830 pItem
= (WXMEASUREITEMSTRUCT
*)new OWNERITEM
;
832 POWNERITEM pMeasureStruct
= (POWNERITEM
)pItem
;
836 // Only owner-drawn control should receive this message
838 wxCHECK( ((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
840 vDc
.SetFont(GetFont());
849 pMeasureStruct
->rclItem
.xRight
= (USHORT
)vWidth
;
850 pMeasureStruct
->rclItem
.xLeft
= 0;
851 pMeasureStruct
->rclItem
.yTop
= 0;
852 pMeasureStruct
->rclItem
.yBottom
= 0;
854 vHeight
= (wxCoord
)(vDc
.GetCharHeight() * 2.5);
855 pMeasureStruct
->rclItem
.yTop
= (USHORT
)vHeight
;
857 return long(MRFROM2SHORT((USHORT
)vHeight
, (USHORT
)vWidth
));
858 } // end of wxListBox::OS2OnMeasure
860 bool wxListBox::OS2OnDraw (
861 WXDRAWITEMSTRUCT
* pItem
864 POWNERITEM pDrawStruct
= (POWNERITEM
)pItem
;
865 LONG lItemID
= pDrawStruct
->idItem
;
870 // Only owner-drawn control should receive this message
872 wxCHECK(((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), false);
876 // The item may be -1 for an empty listbox
881 wxListBoxItem
* pData
= (wxListBoxItem
*)PVOIDFROMMR( ::WinSendMsg( GetHwnd()
883 ,MPFROMLONG(pDrawStruct
->idItem
)
888 wxCHECK(pData
, false );
891 wxPoint
pt1( pDrawStruct
->rclItem
.xLeft
, pDrawStruct
->rclItem
.yTop
);
892 wxPoint
pt2( pDrawStruct
->rclItem
.xRight
, pDrawStruct
->rclItem
.yBottom
);
893 wxRect
vRect( pt1
, pt2
);
895 vDc
.SetHPS(pDrawStruct
->hps
);
897 if (pDrawStruct
->fsAttribute
== pDrawStruct
->fsAttributeOld
)
900 // Entire Item needs to be redrawn (either it has reappeared from
901 // behind another window or is being displayed for the first time
903 eAction
= wxOwnerDrawn::wxODDrawAll
;
905 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
908 // If it is currently selected we let the system handle it
910 eStatus
|= wxOwnerDrawn::wxODSelected
;
912 if (pDrawStruct
->fsAttribute
& MIA_CHECKED
)
915 // If it is currently checked we draw our own
917 eStatus
|= wxOwnerDrawn::wxODChecked
;
918 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_CHECKED
;
920 if (pDrawStruct
->fsAttribute
& MIA_DISABLED
)
923 // If it is currently disabled we let the system handle it
925 eStatus
|= wxOwnerDrawn::wxODDisabled
;
928 // Don't really care about framed (indicationg focus) or NoDismiss
933 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
935 eAction
= wxOwnerDrawn::wxODDrawAll
;
936 eStatus
|= wxOwnerDrawn::wxODSelected
;
938 // Keep the system from trying to highlight with its bogus colors
940 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_HILITED
;
942 else if (!(pDrawStruct
->fsAttribute
& MIA_HILITED
))
944 eAction
= wxOwnerDrawn::wxODDrawAll
;
947 // Keep the system from trying to highlight with its bogus colors
949 pDrawStruct
->fsAttribute
= pDrawStruct
->fsAttributeOld
&= ~MIA_HILITED
;
954 // For now we don't care about anything else
955 // just ignore the entire message!
960 return pData
->OnDrawItem( vDc
962 ,(wxOwnerDrawn::wxODAction
)eAction
963 ,(wxOwnerDrawn::wxODStatus
)eStatus
965 } // end of wxListBox::OS2OnDraw
967 #endif // ndef for wxUSE_OWNER_DRAWN
969 #endif // ndef for wxUSE_LISTBOX