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
= "");
55 wxListBoxItem::wxListBoxItem(
63 // No bitmaps/checkmarks
66 } // end of wxListBoxItem::wxListBoxItem
68 wxOwnerDrawn
* wxListBox::CreateItem(
72 return new wxListBoxItem();
73 } // end of wxListBox::CreateItem
75 #endif //USE_OWNER_DRAWN
77 // ============================================================================
78 // list box control implementation
79 // ============================================================================
82 wxListBox::wxListBox()
86 } // end of wxListBox::wxListBox
88 bool wxListBox::Create(
93 , const wxArrayString
& asChoices
95 , const wxValidator
& rValidator
96 , const wxString
& rsName
99 wxCArrayString
chs(asChoices
);
101 return Create(pParent
, vId
, rPos
, rSize
, chs
.GetCount(), chs
.GetStrings(),
102 lStyle
, rValidator
, rsName
);
105 bool wxListBox::Create(
108 , const wxPoint
& rPos
109 , const wxSize
& rSize
111 , const wxString asChoices
[]
113 , const wxValidator
& rValidator
114 , const wxString
& rsName
123 SetValidator(rValidator
);
127 pParent
->AddChild(this);
129 wxSystemSettings vSettings
;
131 SetBackgroundColour(vSettings
.GetSystemColour(wxSYS_COLOUR_WINDOW
));
132 SetForegroundColour(pParent
->GetForegroundColour());
134 m_windowId
= (vId
== -1) ? (int)NewControlId() : vId
;
138 int nWidth
= rSize
.x
;
139 int nHeight
= rSize
.y
;
141 m_windowStyle
= lStyle
;
145 if (m_windowStyle
& wxCLIP_SIBLINGS
)
146 lStyle
|= WS_CLIPSIBLINGS
;
147 if (m_windowStyle
& wxLB_MULTIPLE
)
148 lStyle
|= LS_MULTIPLESEL
;
149 else if (m_windowStyle
& wxLB_EXTENDED
)
150 lStyle
|= LS_EXTENDEDSEL
;
151 if (m_windowStyle
& wxLB_HSCROLL
)
152 lStyle
|= LS_HORZSCROLL
;
153 if (m_windowStyle
& wxLB_OWNERDRAW
)
154 lStyle
|= LS_OWNERDRAW
;
157 // Without this style, you get unexpected heights, so e.g. constraint layout
158 // doesn't work properly
160 lStyle
|= LS_NOADJUSTPOS
;
162 m_hWnd
= (WXHWND
)::WinCreateWindow( GetWinHwnd(pParent
) // Parent
163 ,WC_LISTBOX
// Default Listbox class
164 ,"LISTBOX" // Control's name
165 ,lStyle
// Initial Style
166 ,0, 0, 0, 0 // Position and size
167 ,GetWinHwnd(pParent
) // Owner
169 ,(HMENU
)m_windowId
// Id
170 ,NULL
// Control Data
171 ,NULL
// Presentation Parameters
179 // Subclass again for purposes of dialog editing mode
185 for (lUi
= 0; lUi
< (LONG
)n
; lUi
++)
187 Append(asChoices
[lUi
]);
189 wxFont
* pTextFont
= new wxFont( 10
197 // Set standard wxWindows colors for Listbox items and highlighting
201 vColour
.Set(wxString("WHITE"));
203 LONG lColor
= (LONG
)vColour
.GetPixel();
205 ::WinSetPresParam( m_hWnd
206 ,PP_HILITEFOREGROUNDCOLOR
210 vColour
.Set(wxString("NAVY"));
211 lColor
= (LONG
)vColour
.GetPixel();
212 ::WinSetPresParam( m_hWnd
213 ,PP_HILITEBACKGROUNDCOLOR
225 } // end of wxListBox::Create
227 wxListBox::~wxListBox()
229 #if wxUSE_OWNER_DRAWN
230 size_t lUiCount
= m_aItems
.Count();
232 while (lUiCount
-- != 0)
234 delete m_aItems
[lUiCount
];
236 #endif // wxUSE_OWNER_DRAWN
237 } // end of wxListBox::~wxListBox
239 void wxListBox::SetupColours()
241 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
242 SetForegroundColour(GetParent()->GetForegroundColour());
243 } // end of wxListBox::SetupColours
245 // ----------------------------------------------------------------------------
246 // implementation of wxListBoxBase methods
247 // ----------------------------------------------------------------------------
249 void wxListBox::DoSetFirstItem(
253 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
254 wxT("invalid index in wxListBox::SetFirstItem") );
256 ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX
, MPFROMLONG(N
), (MPARAM
)0);
257 } // end of wxListBox::DoSetFirstItem
259 void wxListBox::Delete(
263 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
264 wxT("invalid index in wxListBox::Delete") );
266 #if wxUSE_OWNER_DRAWN
268 m_aItems
.RemoveAt(N
);
269 #else // !wxUSE_OWNER_DRAWN
270 if (HasClientObjectData())
272 delete GetClientObject(N
);
274 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
276 ::WinSendMsg(GetHwnd(), LM_DELETEITEM
, (MPARAM
)N
, (MPARAM
)0);
278 } // end of wxListBox::DoSetFirstItem
280 int wxListBox::DoAppend(
281 const wxString
& rsItem
285 SHORT nIndexType
= 0;
287 if (m_windowStyle
& wxLB_SORT
)
288 nIndexType
= LIT_SORTASCENDING
;
290 nIndexType
= LIT_END
;
291 nIndex
= (int)::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)nIndexType
, (MPARAM
)rsItem
.c_str());
294 #if wxUSE_OWNER_DRAWN
295 if (m_windowStyle
& wxLB_OWNERDRAW
)
297 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
); // dummy argument
302 pNewItem
->SetName(rsItem
);
303 m_aItems
.Insert(pNewItem
, nIndex
);
304 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, (MPARAM
)((SHORT
)nIndex
), MPFROMP(pNewItem
));
305 pNewItem
->SetFont(GetFont());
309 } // end of wxListBox::DoAppend
311 void wxListBox::DoSetItems(
312 const wxArrayString
& raChoices
313 , void** ppClientData
316 BOOL bHideAndShow
= IsShown();
319 SHORT nIndexType
= 0;
323 ::WinShowWindow(GetHwnd(), FALSE
);
325 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
326 m_nNumItems
= raChoices
.GetCount();
327 for (i
= 0; i
< m_nNumItems
; i
++)
330 if (m_windowStyle
& wxLB_SORT
)
331 nIndexType
= LIT_SORTASCENDING
;
333 nIndexType
= LIT_END
;
334 ::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)nIndexType
, (MPARAM
)raChoices
[i
].c_str());
338 #if wxUSE_OWNER_DRAWN
339 wxASSERT_MSG(ppClientData
[i
] == NULL
,
340 wxT("Can't use client data with owner-drawn listboxes"));
341 #else // !wxUSE_OWNER_DRAWN
342 ::WinSendMsg(WinUtil_GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(lCount
), MPFROMP(ppClientData
[i
]));
343 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
347 #if wxUSE_OWNER_DRAWN
348 if ( m_windowStyle
& wxLB_OWNERDRAW
)
351 // First delete old items
353 WX_CLEAR_ARRAY(m_aItems
);
356 // Then create new ones
358 for (size_t ui
= 0; ui
< (size_t)m_nNumItems
; ui
++)
360 wxOwnerDrawn
* pNewItem
= CreateItem(ui
);
362 pNewItem
->SetName(raChoices
[ui
]);
363 m_aItems
.Add(pNewItem
);
364 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(ui
), MPFROMP(pNewItem
));
367 #endif // wxUSE_OWNER_DRAWN
368 ::WinShowWindow(GetHwnd(), TRUE
);
369 } // end of wxListBox::DoSetItems
371 int wxListBox::FindString(
372 const wxString
& rsString
380 for (nPos
= 0; nPos
< m_nNumItems
; nPos
++)
382 lTextLength
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)nPos
, (MPARAM
)0));
383 zStr
= new char[lTextLength
+ 1];
384 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT(nPos
, (SHORT
)lTextLength
), (MPARAM
)zStr
);
385 if (rsString
== (char*)zStr
)
393 } // end of wxListBox::FindString
395 void wxListBox::Clear()
397 #if wxUSE_OWNER_DRAWN
398 size_t lUiCount
= m_aItems
.Count();
400 while (lUiCount
-- != 0)
402 delete m_aItems
[lUiCount
];
406 #else // !wxUSE_OWNER_DRAWN
407 if (HasClientObjectData())
409 for (size_t n
= 0; n
< (size_t)m_lNumItems
; n
++)
411 delete GetClientObject(n
);
414 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
415 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
418 } // end of wxListBox::Clear
420 void wxListBox::SetSelection(
425 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
426 wxT("invalid index in wxListBox::SetSelection") );
427 ::WinSendMsg( GetHwnd()
432 if(m_windowStyle
& wxLB_OWNERDRAW
)
434 } // end of wxListBox::SetSelection
436 bool wxListBox::IsSelected(
440 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, FALSE
,
441 wxT("invalid index in wxListBox::Selected") );
445 if (GetWindowStyleFlag() & wxLB_EXTENDED
)
448 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
450 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)(N
- 1), (MPARAM
)0));
454 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
456 return (lItem
== (LONG
)N
&& lItem
!= LIT_NONE
);
457 } // end of wxListBox::IsSelected
459 wxClientData
* wxListBox::DoGetItemClientObject(
463 return (wxClientData
*)DoGetItemClientData(n
);
466 void* wxListBox::DoGetItemClientData(
470 wxCHECK_MSG( n
>= 0 && n
< m_nNumItems
, NULL
,
471 wxT("invalid index in wxListBox::GetClientData") );
473 return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE
, MPFROMLONG(n
), (MPARAM
)0));
474 } // end of wxListBox::DoGetItemClientData
476 void wxListBox::DoSetItemClientObject(
478 , wxClientData
* pClientData
481 DoSetItemClientData( n
484 } // end of wxListBox::DoSetItemClientObject
486 void wxListBox::DoSetItemClientData(
491 wxCHECK_RET( n
>= 0 && n
< m_nNumItems
,
492 wxT("invalid index in wxListBox::SetClientData") );
494 #if wxUSE_OWNER_DRAWN
495 if ( m_windowStyle
& wxLB_OWNERDRAW
)
498 // Client data must be pointer to wxOwnerDrawn, otherwise we would crash
499 // in OnMeasure/OnDraw.
501 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
503 #endif // wxUSE_OWNER_DRAWN
505 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(n
), MPFROMP(pClientData
));
506 } // end of wxListBox::DoSetItemClientData
508 bool wxListBox::HasMultipleSelection() const
510 return (m_windowStyle
& wxLB_MULTIPLE
) || (m_windowStyle
& wxLB_EXTENDED
);
511 } // end of wxListBox::HasMultipleSelection
513 int wxListBox::GetSelections(
514 wxArrayInt
& raSelections
521 raSelections
.Empty();
522 if (HasMultipleSelection())
524 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
530 if (lItem
!= LIT_NONE
)
533 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
542 raSelections
.Alloc(nCount
);
543 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
550 raSelections
.Add((int)lItem
);
551 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
558 raSelections
.Add((int)lItem
);
564 else // single-selection listbox
566 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
572 raSelections
.Add((int)lItem
);
576 } // end of wxListBox::GetSelections
578 int wxListBox::GetSelection() const
580 wxCHECK_MSG( !HasMultipleSelection(),
582 wxT("GetSelection() can't be used with multiple-selection "
583 "listboxes, use GetSelections() instead.") );
585 return(LONGFROMMR(::WinSendMsg( GetHwnd()
591 } // end of wxListBox::GetSelection
593 wxString
wxListBox::GetString(
601 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, "",
602 wxT("invalid index in wxListBox::GetClientData") );
604 lLen
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)N
, (MPARAM
)0));
605 zBuf
= new char[lLen
+ 1];
606 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT((SHORT
)N
, (SHORT
)lLen
), (MPARAM
)zBuf
);
611 } // end of wxListBox::GetString
613 void wxListBox::DoInsertItems(
614 const wxArrayString
& asItems
618 wxCHECK_RET( nPos
>= 0 && nPos
<= m_nNumItems
,
619 wxT("invalid index in wxListBox::InsertItems") );
621 int nItems
= asItems
.GetCount();
623 for (int i
= 0; i
< nItems
; i
++)
625 int nIndex
= (int)::WinSendMsg( GetHwnd()
627 ,MPFROMLONG((LONG
)(i
+ nPos
))
628 ,(MPARAM
)asItems
[i
].c_str()
631 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
);
633 pNewItem
->SetName(asItems
[i
]);
634 pNewItem
->SetFont(GetFont());
635 m_aItems
.Insert(pNewItem
, nIndex
);
636 ::WinSendMsg( GetHwnd()
638 ,(MPARAM
)((SHORT
)nIndex
)
641 m_nNumItems
+= nItems
;
643 } // end of wxListBox::DoInsertItems
645 void wxListBox::SetString(
647 , const wxString
& rsString
650 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
651 wxT("invalid index in wxListBox::SetString") );
654 // Remember the state of the item
656 bool bWasSelected
= IsSelected(N
);
657 void* pOldData
= NULL
;
658 wxClientData
* pOldObjData
= NULL
;
660 if (m_clientDataItemsType
== wxClientData_Void
)
661 pOldData
= GetClientData(N
);
662 else if (m_clientDataItemsType
== wxClientData_Object
)
663 pOldObjData
= GetClientObject(N
);
666 // Delete and recreate it
668 ::WinSendMsg( GetHwnd()
676 if (N
== m_nNumItems
- 1)
679 ::WinSendMsg( GetHwnd()
682 ,(MPARAM
)rsString
.c_str()
686 // Restore the client data
692 else if (pOldObjData
)
698 // We may have lost the selection
703 #if wxUSE_OWNER_DRAWN
704 if (m_windowStyle
& wxLB_OWNERDRAW
)
706 // Update item's text
708 m_aItems
[N
]->SetName(rsString
);
709 #endif //USE_OWNER_DRAWN
710 } // end of wxListBox::SetString
712 int wxListBox::GetCount() const
717 // ----------------------------------------------------------------------------
719 // ----------------------------------------------------------------------------
721 wxSize
wxListBox::DoGetBestSize() const
724 // Find the widest string
731 for (int i
= 0; i
< m_nNumItems
; i
++)
733 wxString
vStr(GetString(i
));
739 if (nLine
> nListbox
)
744 // Give it some reasonable default value if there are no strings in the
751 // The listbox should be slightly larger than the widest string
753 wxGetCharSize( GetHWND()
760 int hListbox
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy
) * (wxMax(m_nNumItems
, 7));
762 return wxSize( nListbox
765 } // end of wxListBox::DoGetBestSize
767 // ----------------------------------------------------------------------------
769 // ----------------------------------------------------------------------------
771 bool wxListBox::OS2Command(
773 , WXWORD
WXUNUSED(wId
))
775 wxEventType eEvtType
;
777 if (uParam
== LN_SELECT
)
779 eEvtType
= wxEVT_COMMAND_LISTBOX_SELECTED
;
781 if (uParam
== LN_ENTER
)
783 eEvtType
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
;
788 // Some event we're not interested in
792 wxCommandEvent
vEvent( eEvtType
796 vEvent
.SetEventObject(this);
798 wxArrayInt aSelections
;
800 int nCount
= GetSelections(aSelections
);
805 if (HasClientObjectData())
806 vEvent
.SetClientObject(GetClientObject(n
));
807 else if ( HasClientUntypedData() )
808 vEvent
.SetClientData(GetClientData(n
));
809 vEvent
.SetString(GetString(n
));
815 vEvent
.m_commandInt
= n
;
816 return GetEventHandler()->ProcessEvent(vEvent
);
817 } // end of wxListBox::OS2Command
819 // ----------------------------------------------------------------------------
820 // wxCheckListBox support
821 // ----------------------------------------------------------------------------
823 #if wxUSE_OWNER_DRAWN
829 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
831 long wxListBox::OS2OnMeasure(
832 WXMEASUREITEMSTRUCT
* pItem
836 pItem
= (WXMEASUREITEMSTRUCT
*)new OWNERITEM
;
838 POWNERITEM pMeasureStruct
= (POWNERITEM
)pItem
;
842 // Only owner-drawn control should receive this message
844 wxCHECK( ((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
846 vDc
.SetFont(GetFont());
855 pMeasureStruct
->rclItem
.xRight
= (USHORT
)vWidth
;
856 pMeasureStruct
->rclItem
.xLeft
= 0;
857 pMeasureStruct
->rclItem
.yTop
= 0;
858 pMeasureStruct
->rclItem
.yBottom
= 0;
860 vHeight
= vDc
.GetCharHeight() * 2.5;
861 pMeasureStruct
->rclItem
.yTop
= (USHORT
)vHeight
;
863 return long(MRFROM2SHORT((USHORT
)vHeight
, (USHORT
)vWidth
));
864 } // end of wxListBox::OS2OnMeasure
866 bool wxListBox::OS2OnDraw (
867 WXDRAWITEMSTRUCT
* pItem
870 POWNERITEM pDrawStruct
= (POWNERITEM
)pItem
;
871 LONG lItemID
= pDrawStruct
->idItem
;
876 // Only owner-drawn control should receive this message
878 wxCHECK(((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
882 // The item may be -1 for an empty listbox
887 wxListBoxItem
* pData
= (wxListBoxItem
*)PVOIDFROMMR( ::WinSendMsg( GetHwnd()
889 ,MPFROMLONG(pDrawStruct
->idItem
)
894 wxCHECK(pData
, FALSE
);
897 wxRect
vRect( wxPoint( pDrawStruct
->rclItem
.xLeft
898 ,pDrawStruct
->rclItem
.yTop
900 ,wxPoint( pDrawStruct
->rclItem
.xRight
901 ,pDrawStruct
->rclItem
.yBottom
905 vDc
.SetHPS(pDrawStruct
->hps
);
907 if (pDrawStruct
->fsAttribute
== pDrawStruct
->fsAttributeOld
)
910 // Entire Item needs to be redrawn (either it has reappeared from
911 // behind another window or is being displayed for the first time
913 eAction
= wxOwnerDrawn::wxODDrawAll
;
915 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
918 // If it is currently selected we let the system handle it
920 eStatus
|= wxOwnerDrawn::wxODSelected
;
922 if (pDrawStruct
->fsAttribute
& MIA_CHECKED
)
925 // If it is currently checked we draw our own
927 eStatus
|= wxOwnerDrawn::wxODChecked
;
928 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_CHECKED
;
930 if (pDrawStruct
->fsAttribute
& MIA_DISABLED
)
933 // If it is currently disabled we let the system handle it
935 eStatus
|= wxOwnerDrawn::wxODDisabled
;
938 // Don't really care about framed (indicationg focus) or NoDismiss
943 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
945 eAction
= wxOwnerDrawn::wxODDrawAll
;
946 eStatus
|= wxOwnerDrawn::wxODSelected
;
948 // Keep the system from trying to highlight with its bogus colors
950 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_HILITED
;
952 else if (!(pDrawStruct
->fsAttribute
& MIA_HILITED
))
954 eAction
= wxOwnerDrawn::wxODDrawAll
;
957 // Keep the system from trying to highlight with its bogus colors
959 pDrawStruct
->fsAttribute
= pDrawStruct
->fsAttributeOld
&= ~MIA_HILITED
;
964 // For now we don't care about anything else
965 // just ignore the entire message!
970 return pData
->OnDrawItem( vDc
972 ,(wxOwnerDrawn::wxODAction
)eAction
973 ,(wxOwnerDrawn::wxODStatus
)eStatus
975 } // end of wxListBox::OS2OnDraw
977 #endif // ndef for wxUSE_OWNER_DRAWN
979 #endif // ndef for wxUSE_LISTBOX