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"
25 #include "wx/scrolwin.h"
31 #include "wx/dynarray.h"
37 #include "wx/ownerdrw.h"
40 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControl
)
42 // ============================================================================
43 // list box item declaration and implementation
44 // ============================================================================
48 class wxListBoxItem
: public wxOwnerDrawn
51 wxListBoxItem(const wxString
& rsStr
= "");
54 wxListBoxItem::wxListBoxItem(
62 // No bitmaps/checkmarks
65 } // end of wxListBoxItem::wxListBoxItem
67 wxOwnerDrawn
* wxListBox::CreateItem(
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(
93 , const wxString asChoices
[]
96 , const wxValidator
& rValidator
98 , const wxString
& rsName
107 SetValidator(rValidator
);
111 pParent
->AddChild(this);
113 wxSystemSettings vSettings
;
115 SetBackgroundColour(vSettings
.GetSystemColour(wxSYS_COLOUR_WINDOW
));
116 SetForegroundColour(pParent
->GetForegroundColour());
118 m_windowId
= (vId
== -1) ? (int)NewControlId() : vId
;
122 int nWidth
= rSize
.x
;
123 int nHeight
= rSize
.y
;
125 m_windowStyle
= lStyle
;
129 if (m_windowStyle
& wxCLIP_SIBLINGS
)
130 lStyle
|= WS_CLIPSIBLINGS
;
131 if (m_windowStyle
& wxLB_MULTIPLE
)
132 lStyle
|= LS_MULTIPLESEL
;
133 else if (m_windowStyle
& wxLB_EXTENDED
)
134 lStyle
|= LS_EXTENDEDSEL
;
135 if (m_windowStyle
& wxLB_HSCROLL
)
136 lStyle
|= LS_HORZSCROLL
;
137 if (m_windowStyle
& wxLB_OWNERDRAW
)
138 lStyle
|= LS_OWNERDRAW
;
141 // Without this style, you get unexpected heights, so e.g. constraint layout
142 // doesn't work properly
144 lStyle
|= LS_NOADJUSTPOS
;
146 m_hWnd
= (WXHWND
)::WinCreateWindow( GetWinHwnd(pParent
) // Parent
147 ,WC_LISTBOX
// Default Listbox class
148 ,"LISTBOX" // Control's name
149 ,lStyle
// Initial Style
150 ,0, 0, 0, 0 // Position and size
151 ,GetWinHwnd(pParent
) // Owner
153 ,(HMENU
)m_windowId
// Id
154 ,NULL
// Control Data
155 ,NULL
// Presentation Parameters
163 // Subclass again for purposes of dialog editing mode
169 for (lUi
= 0; lUi
< (LONG
)n
; lUi
++)
171 Append(asChoices
[lUi
]);
173 wxFont
* pTextFont
= new wxFont( 10
181 // Set standard wxWindows colors for Listbox items and highlighting
185 vColour
.Set(wxString("WHITE"));
187 LONG lColor
= (LONG
)vColour
.GetPixel();
189 ::WinSetPresParam( m_hWnd
190 ,PP_HILITEFOREGROUNDCOLOR
194 vColour
.Set(wxString("NAVY"));
195 lColor
= (LONG
)vColour
.GetPixel();
196 ::WinSetPresParam( m_hWnd
197 ,PP_HILITEBACKGROUNDCOLOR
209 } // end of wxListBox::Create
211 wxListBox::~wxListBox()
213 #if wxUSE_OWNER_DRAWN
214 size_t lUiCount
= m_aItems
.Count();
216 while (lUiCount
-- != 0)
218 delete m_aItems
[lUiCount
];
220 #endif // wxUSE_OWNER_DRAWN
221 } // end of wxListBox::~wxListBox
223 void wxListBox::SetupColours()
225 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
226 SetForegroundColour(GetParent()->GetForegroundColour());
227 } // end of wxListBox::SetupColours
229 // ----------------------------------------------------------------------------
230 // implementation of wxListBoxBase methods
231 // ----------------------------------------------------------------------------
233 void wxListBox::DoSetFirstItem(
237 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
238 wxT("invalid index in wxListBox::SetFirstItem") );
240 ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX
, MPFROMLONG(N
), (MPARAM
)0);
241 } // end of wxListBox::DoSetFirstItem
243 void wxListBox::Delete(
247 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
248 wxT("invalid index in wxListBox::Delete") );
250 #if wxUSE_OWNER_DRAWN
252 m_aItems
.RemoveAt(N
);
253 #else // !wxUSE_OWNER_DRAWN
254 if (HasClientObjectData())
256 delete GetClientObject(N
);
258 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
260 ::WinSendMsg(GetHwnd(), LM_DELETEITEM
, (MPARAM
)N
, (MPARAM
)0);
262 } // end of wxListBox::DoSetFirstItem
264 int wxListBox::DoAppend(
265 const wxString
& rsItem
269 SHORT nIndexType
= 0;
271 if (m_windowStyle
& wxLB_SORT
)
272 nIndexType
= LIT_SORTASCENDING
;
274 nIndexType
= LIT_END
;
275 nIndex
= (int)::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)nIndexType
, (MPARAM
)rsItem
.c_str());
278 #if wxUSE_OWNER_DRAWN
279 if (m_windowStyle
& wxLB_OWNERDRAW
)
281 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
); // dummy argument
283 pNewItem
->SetName(rsItem
);
284 m_aItems
.Insert(pNewItem
, nIndex
);
285 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, (MPARAM
)((SHORT
)nIndex
), MPFROMP(pNewItem
));
286 pNewItem
->SetFont(GetFont());
290 } // end of wxListBox::DoAppend
292 void wxListBox::DoSetItems(
293 const wxArrayString
& raChoices
294 , void** ppClientData
297 BOOL bHideAndShow
= IsShown();
300 SHORT nIndexType
= 0;
304 ::WinShowWindow(GetHwnd(), FALSE
);
306 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
307 m_nNumItems
= raChoices
.GetCount();
308 for (i
= 0; i
< m_nNumItems
; i
++)
311 if (m_windowStyle
& wxLB_SORT
)
312 nIndexType
= LIT_SORTASCENDING
;
314 nIndexType
= LIT_END
;
315 ::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)nIndexType
, (MPARAM
)raChoices
[i
].c_str());
319 #if wxUSE_OWNER_DRAWN
320 wxASSERT_MSG(ppClientData
[i
] == NULL
,
321 wxT("Can't use client data with owner-drawn listboxes"));
322 #else // !wxUSE_OWNER_DRAWN
323 ::WinSendMsg(WinUtil_GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(lCount
), MPFROMP(ppClientData
[i
]));
324 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
328 #if wxUSE_OWNER_DRAWN
329 if ( m_windowStyle
& wxLB_OWNERDRAW
)
332 // First delete old items
334 WX_CLEAR_ARRAY(m_aItems
);
337 // Then create new ones
339 for (size_t ui
= 0; ui
< (size_t)m_nNumItems
; ui
++)
341 wxOwnerDrawn
* pNewItem
= CreateItem(ui
);
343 pNewItem
->SetName(raChoices
[ui
]);
344 m_aItems
.Add(pNewItem
);
345 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(ui
), MPFROMP(pNewItem
));
348 #endif // wxUSE_OWNER_DRAWN
349 ::WinShowWindow(GetHwnd(), TRUE
);
350 } // end of wxListBox::DoSetItems
352 int wxListBox::FindString(
353 const wxString
& rsString
361 for (nPos
= 0; nPos
< m_nNumItems
; nPos
++)
363 lTextLength
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)nPos
, (MPARAM
)0));
364 zStr
= new char[lTextLength
+ 1];
365 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT(nPos
, (SHORT
)lTextLength
), (MPARAM
)zStr
);
366 if (rsString
== (char*)zStr
)
374 } // end of wxListBox::FindString
376 void wxListBox::Clear()
378 #if wxUSE_OWNER_DRAWN
379 size_t lUiCount
= m_aItems
.Count();
381 while (lUiCount
-- != 0)
383 delete m_aItems
[lUiCount
];
387 #else // !wxUSE_OWNER_DRAWN
388 if (HasClientObjectData())
390 for (size_t n
= 0; n
< (size_t)m_lNumItems
; n
++)
392 delete GetClientObject(n
);
395 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
396 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
399 } // end of wxListBox::Clear
401 void wxListBox::SetSelection(
406 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
407 wxT("invalid index in wxListBox::SetSelection") );
408 ::WinSendMsg( GetHwnd()
413 if(m_windowStyle
& wxLB_OWNERDRAW
)
415 } // end of wxListBox::SetSelection
417 bool wxListBox::IsSelected(
421 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, FALSE
,
422 wxT("invalid index in wxListBox::Selected") );
426 if (GetWindowStyleFlag() & wxLB_EXTENDED
)
429 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
431 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)(N
- 1), (MPARAM
)0));
435 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
437 return (lItem
== (LONG
)N
&& lItem
!= LIT_NONE
);
438 } // end of wxListBox::IsSelected
440 wxClientData
* wxListBox::DoGetItemClientObject(
444 return (wxClientData
*)DoGetItemClientData(n
);
447 void* wxListBox::DoGetItemClientData(
451 wxCHECK_MSG( n
>= 0 && n
< m_nNumItems
, NULL
,
452 wxT("invalid index in wxListBox::GetClientData") );
454 return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE
, MPFROMLONG(n
), (MPARAM
)0));
455 } // end of wxListBox::DoGetItemClientData
457 void wxListBox::DoSetItemClientObject(
459 , wxClientData
* pClientData
462 DoSetItemClientData( n
465 } // end of wxListBox::DoSetItemClientObject
467 void wxListBox::DoSetItemClientData(
472 wxCHECK_RET( n
>= 0 && n
< m_nNumItems
,
473 wxT("invalid index in wxListBox::SetClientData") );
475 #if wxUSE_OWNER_DRAWN
476 if ( m_windowStyle
& wxLB_OWNERDRAW
)
479 // Client data must be pointer to wxOwnerDrawn, otherwise we would crash
480 // in OnMeasure/OnDraw.
482 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
484 #endif // wxUSE_OWNER_DRAWN
486 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(n
), MPFROMP(pClientData
));
487 } // end of wxListBox::DoSetItemClientData
489 bool wxListBox::HasMultipleSelection() const
491 return (m_windowStyle
& wxLB_MULTIPLE
) || (m_windowStyle
& wxLB_EXTENDED
);
492 } // end of wxListBox::HasMultipleSelection
494 int wxListBox::GetSelections(
495 wxArrayInt
& raSelections
502 raSelections
.Empty();
503 if (HasMultipleSelection())
505 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
511 if (lItem
!= LIT_NONE
)
514 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
523 raSelections
.Alloc(nCount
);
524 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
531 raSelections
.Add((int)lItem
);
532 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
539 raSelections
.Add((int)lItem
);
545 else // single-selection listbox
547 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
553 raSelections
.Add((int)lItem
);
557 } // end of wxListBox::GetSelections
559 int wxListBox::GetSelection() const
561 wxCHECK_MSG( !HasMultipleSelection(),
563 wxT("GetSelection() can't be used with multiple-selection "
564 "listboxes, use GetSelections() instead.") );
566 return(LONGFROMMR(::WinSendMsg( GetHwnd()
572 } // end of wxListBox::GetSelection
574 wxString
wxListBox::GetString(
582 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, "",
583 wxT("invalid index in wxListBox::GetClientData") );
585 lLen
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)N
, (MPARAM
)0));
586 zBuf
= new char[lLen
+ 1];
587 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT((SHORT
)N
, (SHORT
)lLen
), (MPARAM
)zBuf
);
592 } // end of wxListBox::GetString
594 void wxListBox::DoInsertItems(
595 const wxArrayString
& asItems
599 wxCHECK_RET( nPos
>= 0 && nPos
<= m_nNumItems
,
600 wxT("invalid index in wxListBox::InsertItems") );
602 int nItems
= asItems
.GetCount();
604 for (int i
= 0; i
< nItems
; i
++)
606 int nIndex
= (int)::WinSendMsg( GetHwnd()
608 ,MPFROMLONG((LONG
)(i
+ nPos
))
609 ,(MPARAM
)asItems
[i
].c_str()
612 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
);
614 pNewItem
->SetName(asItems
[i
]);
615 pNewItem
->SetFont(GetFont());
616 m_aItems
.Insert(pNewItem
, nIndex
);
617 ::WinSendMsg( GetHwnd()
619 ,(MPARAM
)((SHORT
)nIndex
)
622 m_nNumItems
+= nItems
;
624 } // end of wxListBox::DoInsertItems
626 void wxListBox::SetString(
628 , const wxString
& rsString
631 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
632 wxT("invalid index in wxListBox::SetString") );
635 // Remember the state of the item
637 bool bWasSelected
= IsSelected(N
);
638 void* pOldData
= NULL
;
639 wxClientData
* pOldObjData
= NULL
;
641 if (m_clientDataItemsType
== wxClientData_Void
)
642 pOldData
= GetClientData(N
);
643 else if (m_clientDataItemsType
== wxClientData_Object
)
644 pOldObjData
= GetClientObject(N
);
647 // Delete and recreate it
649 ::WinSendMsg( GetHwnd()
657 if (N
== m_nNumItems
- 1)
660 ::WinSendMsg( GetHwnd()
663 ,(MPARAM
)rsString
.c_str()
667 // Restore the client data
673 else if (pOldObjData
)
679 // We may have lost the selection
684 #if wxUSE_OWNER_DRAWN
685 if (m_windowStyle
& wxLB_OWNERDRAW
)
687 // Update item's text
689 m_aItems
[N
]->SetName(rsString
);
690 #endif //USE_OWNER_DRAWN
691 } // end of wxListBox::SetString
693 int wxListBox::GetCount() const
698 // ----------------------------------------------------------------------------
700 // ----------------------------------------------------------------------------
702 wxSize
wxListBox::DoGetBestSize() const
705 // Find the widest string
712 for (int i
= 0; i
< m_nNumItems
; i
++)
714 wxString
vStr(GetString(i
));
720 if (nLine
> nListbox
)
725 // Give it some reasonable default value if there are no strings in the
732 // The listbox should be slightly larger than the widest string
734 wxGetCharSize( GetHWND()
741 int hListbox
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy
) * (wxMax(m_nNumItems
, 7));
743 return wxSize( nListbox
746 } // end of wxListBox::DoGetBestSize
748 // ----------------------------------------------------------------------------
750 // ----------------------------------------------------------------------------
752 bool wxListBox::OS2Command(
754 , WXWORD
WXUNUSED(wId
))
756 wxEventType eEvtType
;
758 if (uParam
== LN_SELECT
)
760 eEvtType
= wxEVT_COMMAND_LISTBOX_SELECTED
;
762 if (uParam
== LN_ENTER
)
764 eEvtType
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
;
769 // Some event we're not interested in
773 wxCommandEvent
vEvent( eEvtType
777 vEvent
.SetEventObject(this);
779 wxArrayInt aSelections
;
781 int nCount
= GetSelections(aSelections
);
786 if (HasClientObjectData())
787 vEvent
.SetClientObject(GetClientObject(n
));
788 else if ( HasClientUntypedData() )
789 vEvent
.SetClientData(GetClientData(n
));
790 vEvent
.SetString(GetString(n
));
796 vEvent
.m_commandInt
= n
;
797 return GetEventHandler()->ProcessEvent(vEvent
);
798 } // end of wxListBox::OS2Command
800 // ----------------------------------------------------------------------------
801 // wxCheckListBox support
802 // ----------------------------------------------------------------------------
804 #if wxUSE_OWNER_DRAWN
810 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
812 bool wxListBox::OS2OnMeasure(
813 WXMEASUREITEMSTRUCT
* pItem
817 pItem
= (WXMEASUREITEMSTRUCT
*)new OWNERITEM
;
819 POWNERITEM pMeasureStruct
= (POWNERITEM
)pItem
;
823 // Only owner-drawn control should receive this message
825 wxCHECK( ((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
827 vDc
.SetFont(GetFont());
831 pMeasureStruct
->rclItem
.xRight
= 0;
832 pMeasureStruct
->rclItem
.xLeft
= 0;
833 pMeasureStruct
->rclItem
.yTop
= 0;
834 pMeasureStruct
->rclItem
.yBottom
= 0;
836 vHeight
= vDc
.GetCharHeight() * 2.5;
837 pMeasureStruct
->rclItem
.yTop
= vHeight
;
839 ::WinSendMsg( GetHWND()
842 ,MPFROMLONG(pMeasureStruct
->idItem
)
845 } // end of wxListBox::OS2OnMeasure
847 bool wxListBox::OS2OnDraw (
848 WXDRAWITEMSTRUCT
* pItem
851 POWNERITEM pDrawStruct
= (POWNERITEM
)pItem
;
852 LONG lItemID
= pDrawStruct
->idItem
;
857 // Only owner-drawn control should receive this message
859 wxCHECK(((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
863 // The item may be -1 for an empty listbox
868 wxListBoxItem
* pData
= (wxListBoxItem
*)PVOIDFROMMR( ::WinSendMsg( GetHwnd()
870 ,MPFROMLONG(pDrawStruct
->idItem
)
875 wxCHECK(pData
, FALSE
);
878 wxRect
vRect( wxPoint( pDrawStruct
->rclItem
.xLeft
879 ,pDrawStruct
->rclItem
.yTop
881 ,wxPoint( pDrawStruct
->rclItem
.xRight
882 ,pDrawStruct
->rclItem
.yBottom
886 vDc
.SetHPS(pDrawStruct
->hps
);
888 if (pDrawStruct
->fsAttribute
== pDrawStruct
->fsAttributeOld
)
891 // Entire Item needs to be redrawn (either it has reappeared from
892 // behind another window or is being displayed for the first time
894 eAction
= wxOwnerDrawn::wxODDrawAll
;
896 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
899 // If it is currently selected we let the system handle it
901 eStatus
|= wxOwnerDrawn::wxODSelected
;
903 if (pDrawStruct
->fsAttribute
& MIA_CHECKED
)
906 // If it is currently checked we draw our own
908 eStatus
|= wxOwnerDrawn::wxODChecked
;
909 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_CHECKED
;
911 if (pDrawStruct
->fsAttribute
& MIA_DISABLED
)
914 // If it is currently disabled we let the system handle it
916 eStatus
|= wxOwnerDrawn::wxODDisabled
;
919 // Don't really care about framed (indicationg focus) or NoDismiss
924 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
926 eAction
= wxOwnerDrawn::wxODDrawAll
;
927 eStatus
|= wxOwnerDrawn::wxODSelected
;
929 // Keep the system from trying to highlight with its bogus colors
931 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_HILITED
;
933 else if (!(pDrawStruct
->fsAttribute
& MIA_HILITED
))
935 eAction
= wxOwnerDrawn::wxODDrawAll
;
938 // Keep the system from trying to highlight with its bogus colors
940 pDrawStruct
->fsAttribute
= pDrawStruct
->fsAttributeOld
&= ~MIA_HILITED
;
945 // For now we don't care about anything else
946 // just ignore the entire message!
951 return pData
->OnDrawItem( vDc
953 ,(wxOwnerDrawn::wxODAction
)eAction
954 ,(wxOwnerDrawn::wxODStatus
)eStatus
956 } // end of wxListBox::OS2OnDraw
958 #endif // ndef for wxUSE_OWNER_DRAWN
960 #endif // ndef for wxUSE_LISTBOX