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(
94 , const wxString asChoices
[]
97 , const wxValidator
& rValidator
99 , const wxString
& rsName
108 SetValidator(rValidator
);
112 pParent
->AddChild(this);
114 wxSystemSettings vSettings
;
116 SetBackgroundColour(vSettings
.GetSystemColour(wxSYS_COLOUR_WINDOW
));
117 SetForegroundColour(pParent
->GetForegroundColour());
119 m_windowId
= (vId
== -1) ? (int)NewControlId() : vId
;
123 int nWidth
= rSize
.x
;
124 int nHeight
= rSize
.y
;
126 m_windowStyle
= lStyle
;
130 if (m_windowStyle
& wxCLIP_SIBLINGS
)
131 lStyle
|= WS_CLIPSIBLINGS
;
132 if (m_windowStyle
& wxLB_MULTIPLE
)
133 lStyle
|= LS_MULTIPLESEL
;
134 else if (m_windowStyle
& wxLB_EXTENDED
)
135 lStyle
|= LS_EXTENDEDSEL
;
136 if (m_windowStyle
& wxLB_HSCROLL
)
137 lStyle
|= LS_HORZSCROLL
;
138 if (m_windowStyle
& wxLB_OWNERDRAW
)
139 lStyle
|= LS_OWNERDRAW
;
142 // Without this style, you get unexpected heights, so e.g. constraint layout
143 // doesn't work properly
145 lStyle
|= LS_NOADJUSTPOS
;
147 m_hWnd
= (WXHWND
)::WinCreateWindow( GetWinHwnd(pParent
) // Parent
148 ,WC_LISTBOX
// Default Listbox class
149 ,"LISTBOX" // Control's name
150 ,lStyle
// Initial Style
151 ,0, 0, 0, 0 // Position and size
152 ,GetWinHwnd(pParent
) // Owner
154 ,(HMENU
)m_windowId
// Id
155 ,NULL
// Control Data
156 ,NULL
// Presentation Parameters
164 // Subclass again for purposes of dialog editing mode
170 for (lUi
= 0; lUi
< (LONG
)n
; lUi
++)
172 Append(asChoices
[lUi
]);
174 wxFont
* pTextFont
= new wxFont( 10
182 // Set standard wxWindows colors for Listbox items and highlighting
186 vColour
.Set(wxString("WHITE"));
188 LONG lColor
= (LONG
)vColour
.GetPixel();
190 ::WinSetPresParam( m_hWnd
191 ,PP_HILITEFOREGROUNDCOLOR
195 vColour
.Set(wxString("NAVY"));
196 lColor
= (LONG
)vColour
.GetPixel();
197 ::WinSetPresParam( m_hWnd
198 ,PP_HILITEBACKGROUNDCOLOR
210 } // end of wxListBox::Create
212 wxListBox::~wxListBox()
214 #if wxUSE_OWNER_DRAWN
215 size_t lUiCount
= m_aItems
.Count();
217 while (lUiCount
-- != 0)
219 delete m_aItems
[lUiCount
];
221 #endif // wxUSE_OWNER_DRAWN
222 } // end of wxListBox::~wxListBox
224 void wxListBox::SetupColours()
226 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
227 SetForegroundColour(GetParent()->GetForegroundColour());
228 } // end of wxListBox::SetupColours
230 // ----------------------------------------------------------------------------
231 // implementation of wxListBoxBase methods
232 // ----------------------------------------------------------------------------
234 void wxListBox::DoSetFirstItem(
238 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
239 wxT("invalid index in wxListBox::SetFirstItem") );
241 ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX
, MPFROMLONG(N
), (MPARAM
)0);
242 } // end of wxListBox::DoSetFirstItem
244 void wxListBox::Delete(
248 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
249 wxT("invalid index in wxListBox::Delete") );
251 #if wxUSE_OWNER_DRAWN
253 m_aItems
.RemoveAt(N
);
254 #else // !wxUSE_OWNER_DRAWN
255 if (HasClientObjectData())
257 delete GetClientObject(N
);
259 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
261 ::WinSendMsg(GetHwnd(), LM_DELETEITEM
, (MPARAM
)N
, (MPARAM
)0);
263 } // end of wxListBox::DoSetFirstItem
265 int wxListBox::DoAppend(
266 const wxString
& rsItem
270 SHORT nIndexType
= 0;
272 if (m_windowStyle
& wxLB_SORT
)
273 nIndexType
= LIT_SORTASCENDING
;
275 nIndexType
= LIT_END
;
276 nIndex
= (int)::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)nIndexType
, (MPARAM
)rsItem
.c_str());
279 #if wxUSE_OWNER_DRAWN
280 if (m_windowStyle
& wxLB_OWNERDRAW
)
282 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
); // dummy argument
287 pNewItem
->SetName(rsItem
);
288 m_aItems
.Insert(pNewItem
, nIndex
);
289 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, (MPARAM
)((SHORT
)nIndex
), MPFROMP(pNewItem
));
290 pNewItem
->SetFont(GetFont());
294 } // end of wxListBox::DoAppend
296 void wxListBox::DoSetItems(
297 const wxArrayString
& raChoices
298 , void** ppClientData
301 BOOL bHideAndShow
= IsShown();
304 SHORT nIndexType
= 0;
308 ::WinShowWindow(GetHwnd(), FALSE
);
310 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
311 m_nNumItems
= raChoices
.GetCount();
312 for (i
= 0; i
< m_nNumItems
; i
++)
315 if (m_windowStyle
& wxLB_SORT
)
316 nIndexType
= LIT_SORTASCENDING
;
318 nIndexType
= LIT_END
;
319 ::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)nIndexType
, (MPARAM
)raChoices
[i
].c_str());
323 #if wxUSE_OWNER_DRAWN
324 wxASSERT_MSG(ppClientData
[i
] == NULL
,
325 wxT("Can't use client data with owner-drawn listboxes"));
326 #else // !wxUSE_OWNER_DRAWN
327 ::WinSendMsg(WinUtil_GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(lCount
), MPFROMP(ppClientData
[i
]));
328 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
332 #if wxUSE_OWNER_DRAWN
333 if ( m_windowStyle
& wxLB_OWNERDRAW
)
336 // First delete old items
338 WX_CLEAR_ARRAY(m_aItems
);
341 // Then create new ones
343 for (size_t ui
= 0; ui
< (size_t)m_nNumItems
; ui
++)
345 wxOwnerDrawn
* pNewItem
= CreateItem(ui
);
347 pNewItem
->SetName(raChoices
[ui
]);
348 m_aItems
.Add(pNewItem
);
349 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(ui
), MPFROMP(pNewItem
));
352 #endif // wxUSE_OWNER_DRAWN
353 ::WinShowWindow(GetHwnd(), TRUE
);
354 } // end of wxListBox::DoSetItems
356 int wxListBox::FindString(
357 const wxString
& rsString
365 for (nPos
= 0; nPos
< m_nNumItems
; nPos
++)
367 lTextLength
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)nPos
, (MPARAM
)0));
368 zStr
= new char[lTextLength
+ 1];
369 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT(nPos
, (SHORT
)lTextLength
), (MPARAM
)zStr
);
370 if (rsString
== (char*)zStr
)
378 } // end of wxListBox::FindString
380 void wxListBox::Clear()
382 #if wxUSE_OWNER_DRAWN
383 size_t lUiCount
= m_aItems
.Count();
385 while (lUiCount
-- != 0)
387 delete m_aItems
[lUiCount
];
391 #else // !wxUSE_OWNER_DRAWN
392 if (HasClientObjectData())
394 for (size_t n
= 0; n
< (size_t)m_lNumItems
; n
++)
396 delete GetClientObject(n
);
399 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
400 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
403 } // end of wxListBox::Clear
405 void wxListBox::SetSelection(
410 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
411 wxT("invalid index in wxListBox::SetSelection") );
412 ::WinSendMsg( GetHwnd()
417 if(m_windowStyle
& wxLB_OWNERDRAW
)
419 } // end of wxListBox::SetSelection
421 bool wxListBox::IsSelected(
425 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, FALSE
,
426 wxT("invalid index in wxListBox::Selected") );
430 if (GetWindowStyleFlag() & wxLB_EXTENDED
)
433 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
435 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)(N
- 1), (MPARAM
)0));
439 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
441 return (lItem
== (LONG
)N
&& lItem
!= LIT_NONE
);
442 } // end of wxListBox::IsSelected
444 wxClientData
* wxListBox::DoGetItemClientObject(
448 return (wxClientData
*)DoGetItemClientData(n
);
451 void* wxListBox::DoGetItemClientData(
455 wxCHECK_MSG( n
>= 0 && n
< m_nNumItems
, NULL
,
456 wxT("invalid index in wxListBox::GetClientData") );
458 return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE
, MPFROMLONG(n
), (MPARAM
)0));
459 } // end of wxListBox::DoGetItemClientData
461 void wxListBox::DoSetItemClientObject(
463 , wxClientData
* pClientData
466 DoSetItemClientData( n
469 } // end of wxListBox::DoSetItemClientObject
471 void wxListBox::DoSetItemClientData(
476 wxCHECK_RET( n
>= 0 && n
< m_nNumItems
,
477 wxT("invalid index in wxListBox::SetClientData") );
479 #if wxUSE_OWNER_DRAWN
480 if ( m_windowStyle
& wxLB_OWNERDRAW
)
483 // Client data must be pointer to wxOwnerDrawn, otherwise we would crash
484 // in OnMeasure/OnDraw.
486 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
488 #endif // wxUSE_OWNER_DRAWN
490 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(n
), MPFROMP(pClientData
));
491 } // end of wxListBox::DoSetItemClientData
493 bool wxListBox::HasMultipleSelection() const
495 return (m_windowStyle
& wxLB_MULTIPLE
) || (m_windowStyle
& wxLB_EXTENDED
);
496 } // end of wxListBox::HasMultipleSelection
498 int wxListBox::GetSelections(
499 wxArrayInt
& raSelections
506 raSelections
.Empty();
507 if (HasMultipleSelection())
509 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
515 if (lItem
!= LIT_NONE
)
518 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
527 raSelections
.Alloc(nCount
);
528 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
535 raSelections
.Add((int)lItem
);
536 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
543 raSelections
.Add((int)lItem
);
549 else // single-selection listbox
551 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
557 raSelections
.Add((int)lItem
);
561 } // end of wxListBox::GetSelections
563 int wxListBox::GetSelection() const
565 wxCHECK_MSG( !HasMultipleSelection(),
567 wxT("GetSelection() can't be used with multiple-selection "
568 "listboxes, use GetSelections() instead.") );
570 return(LONGFROMMR(::WinSendMsg( GetHwnd()
576 } // end of wxListBox::GetSelection
578 wxString
wxListBox::GetString(
586 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, "",
587 wxT("invalid index in wxListBox::GetClientData") );
589 lLen
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)N
, (MPARAM
)0));
590 zBuf
= new char[lLen
+ 1];
591 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT((SHORT
)N
, (SHORT
)lLen
), (MPARAM
)zBuf
);
596 } // end of wxListBox::GetString
598 void wxListBox::DoInsertItems(
599 const wxArrayString
& asItems
603 wxCHECK_RET( nPos
>= 0 && nPos
<= m_nNumItems
,
604 wxT("invalid index in wxListBox::InsertItems") );
606 int nItems
= asItems
.GetCount();
608 for (int i
= 0; i
< nItems
; i
++)
610 int nIndex
= (int)::WinSendMsg( GetHwnd()
612 ,MPFROMLONG((LONG
)(i
+ nPos
))
613 ,(MPARAM
)asItems
[i
].c_str()
616 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
);
618 pNewItem
->SetName(asItems
[i
]);
619 pNewItem
->SetFont(GetFont());
620 m_aItems
.Insert(pNewItem
, nIndex
);
621 ::WinSendMsg( GetHwnd()
623 ,(MPARAM
)((SHORT
)nIndex
)
626 m_nNumItems
+= nItems
;
628 } // end of wxListBox::DoInsertItems
630 void wxListBox::SetString(
632 , const wxString
& rsString
635 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
636 wxT("invalid index in wxListBox::SetString") );
639 // Remember the state of the item
641 bool bWasSelected
= IsSelected(N
);
642 void* pOldData
= NULL
;
643 wxClientData
* pOldObjData
= NULL
;
645 if (m_clientDataItemsType
== wxClientData_Void
)
646 pOldData
= GetClientData(N
);
647 else if (m_clientDataItemsType
== wxClientData_Object
)
648 pOldObjData
= GetClientObject(N
);
651 // Delete and recreate it
653 ::WinSendMsg( GetHwnd()
661 if (N
== m_nNumItems
- 1)
664 ::WinSendMsg( GetHwnd()
667 ,(MPARAM
)rsString
.c_str()
671 // Restore the client data
677 else if (pOldObjData
)
683 // We may have lost the selection
688 #if wxUSE_OWNER_DRAWN
689 if (m_windowStyle
& wxLB_OWNERDRAW
)
691 // Update item's text
693 m_aItems
[N
]->SetName(rsString
);
694 #endif //USE_OWNER_DRAWN
695 } // end of wxListBox::SetString
697 int wxListBox::GetCount() const
702 // ----------------------------------------------------------------------------
704 // ----------------------------------------------------------------------------
706 wxSize
wxListBox::DoGetBestSize() const
709 // Find the widest string
716 for (int i
= 0; i
< m_nNumItems
; i
++)
718 wxString
vStr(GetString(i
));
724 if (nLine
> nListbox
)
729 // Give it some reasonable default value if there are no strings in the
736 // The listbox should be slightly larger than the widest string
738 wxGetCharSize( GetHWND()
745 int hListbox
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy
) * (wxMax(m_nNumItems
, 7));
747 return wxSize( nListbox
750 } // end of wxListBox::DoGetBestSize
752 // ----------------------------------------------------------------------------
754 // ----------------------------------------------------------------------------
756 bool wxListBox::OS2Command(
758 , WXWORD
WXUNUSED(wId
))
760 wxEventType eEvtType
;
762 if (uParam
== LN_SELECT
)
764 eEvtType
= wxEVT_COMMAND_LISTBOX_SELECTED
;
766 if (uParam
== LN_ENTER
)
768 eEvtType
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
;
773 // Some event we're not interested in
777 wxCommandEvent
vEvent( eEvtType
781 vEvent
.SetEventObject(this);
783 wxArrayInt aSelections
;
785 int nCount
= GetSelections(aSelections
);
790 if (HasClientObjectData())
791 vEvent
.SetClientObject(GetClientObject(n
));
792 else if ( HasClientUntypedData() )
793 vEvent
.SetClientData(GetClientData(n
));
794 vEvent
.SetString(GetString(n
));
800 vEvent
.m_commandInt
= n
;
801 return GetEventHandler()->ProcessEvent(vEvent
);
802 } // end of wxListBox::OS2Command
804 // ----------------------------------------------------------------------------
805 // wxCheckListBox support
806 // ----------------------------------------------------------------------------
808 #if wxUSE_OWNER_DRAWN
814 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
816 long wxListBox::OS2OnMeasure(
817 WXMEASUREITEMSTRUCT
* pItem
821 pItem
= (WXMEASUREITEMSTRUCT
*)new OWNERITEM
;
823 POWNERITEM pMeasureStruct
= (POWNERITEM
)pItem
;
827 // Only owner-drawn control should receive this message
829 wxCHECK( ((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
831 vDc
.SetFont(GetFont());
840 pMeasureStruct
->rclItem
.xRight
= (USHORT
)vWidth
;
841 pMeasureStruct
->rclItem
.xLeft
= 0;
842 pMeasureStruct
->rclItem
.yTop
= 0;
843 pMeasureStruct
->rclItem
.yBottom
= 0;
845 vHeight
= vDc
.GetCharHeight() * 2.5;
846 pMeasureStruct
->rclItem
.yTop
= (USHORT
)vHeight
;
848 return long(MRFROM2SHORT((USHORT
)vHeight
, (USHORT
)vWidth
));
849 } // end of wxListBox::OS2OnMeasure
851 bool wxListBox::OS2OnDraw (
852 WXDRAWITEMSTRUCT
* pItem
855 POWNERITEM pDrawStruct
= (POWNERITEM
)pItem
;
856 LONG lItemID
= pDrawStruct
->idItem
;
861 // Only owner-drawn control should receive this message
863 wxCHECK(((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
867 // The item may be -1 for an empty listbox
872 wxListBoxItem
* pData
= (wxListBoxItem
*)PVOIDFROMMR( ::WinSendMsg( GetHwnd()
874 ,MPFROMLONG(pDrawStruct
->idItem
)
879 wxCHECK(pData
, FALSE
);
882 wxRect
vRect( wxPoint( pDrawStruct
->rclItem
.xLeft
883 ,pDrawStruct
->rclItem
.yTop
885 ,wxPoint( pDrawStruct
->rclItem
.xRight
886 ,pDrawStruct
->rclItem
.yBottom
890 vDc
.SetHPS(pDrawStruct
->hps
);
892 if (pDrawStruct
->fsAttribute
== pDrawStruct
->fsAttributeOld
)
895 // Entire Item needs to be redrawn (either it has reappeared from
896 // behind another window or is being displayed for the first time
898 eAction
= wxOwnerDrawn::wxODDrawAll
;
900 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
903 // If it is currently selected we let the system handle it
905 eStatus
|= wxOwnerDrawn::wxODSelected
;
907 if (pDrawStruct
->fsAttribute
& MIA_CHECKED
)
910 // If it is currently checked we draw our own
912 eStatus
|= wxOwnerDrawn::wxODChecked
;
913 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_CHECKED
;
915 if (pDrawStruct
->fsAttribute
& MIA_DISABLED
)
918 // If it is currently disabled we let the system handle it
920 eStatus
|= wxOwnerDrawn::wxODDisabled
;
923 // Don't really care about framed (indicationg focus) or NoDismiss
928 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
930 eAction
= wxOwnerDrawn::wxODDrawAll
;
931 eStatus
|= wxOwnerDrawn::wxODSelected
;
933 // Keep the system from trying to highlight with its bogus colors
935 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_HILITED
;
937 else if (!(pDrawStruct
->fsAttribute
& MIA_HILITED
))
939 eAction
= wxOwnerDrawn::wxODDrawAll
;
942 // Keep the system from trying to highlight with its bogus colors
944 pDrawStruct
->fsAttribute
= pDrawStruct
->fsAttributeOld
&= ~MIA_HILITED
;
949 // For now we don't care about anything else
950 // just ignore the entire message!
955 return pData
->OnDrawItem( vDc
957 ,(wxOwnerDrawn::wxODAction
)eAction
958 ,(wxOwnerDrawn::wxODStatus
)eStatus
960 } // end of wxListBox::OS2OnDraw
962 #endif // ndef for wxUSE_OWNER_DRAWN
964 #endif // ndef for wxUSE_LISTBOX