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
[]
96 , const wxValidator
& rValidator
97 , const wxString
& rsName
106 SetValidator(rValidator
);
110 pParent
->AddChild(this);
112 wxSystemSettings vSettings
;
114 SetBackgroundColour(vSettings
.GetSystemColour(wxSYS_COLOUR_WINDOW
));
115 SetForegroundColour(pParent
->GetForegroundColour());
117 m_windowId
= (vId
== -1) ? (int)NewControlId() : vId
;
121 int nWidth
= rSize
.x
;
122 int nHeight
= rSize
.y
;
124 m_windowStyle
= lStyle
;
128 if (m_windowStyle
& wxCLIP_SIBLINGS
)
129 lStyle
|= WS_CLIPSIBLINGS
;
130 if (m_windowStyle
& wxLB_MULTIPLE
)
131 lStyle
|= LS_MULTIPLESEL
;
132 else if (m_windowStyle
& wxLB_EXTENDED
)
133 lStyle
|= LS_EXTENDEDSEL
;
134 if (m_windowStyle
& wxLB_HSCROLL
)
135 lStyle
|= LS_HORZSCROLL
;
136 if (m_windowStyle
& wxLB_OWNERDRAW
)
137 lStyle
|= LS_OWNERDRAW
;
140 // Without this style, you get unexpected heights, so e.g. constraint layout
141 // doesn't work properly
143 lStyle
|= LS_NOADJUSTPOS
;
145 m_hWnd
= (WXHWND
)::WinCreateWindow( GetWinHwnd(pParent
) // Parent
146 ,WC_LISTBOX
// Default Listbox class
147 ,"LISTBOX" // Control's name
148 ,lStyle
// Initial Style
149 ,0, 0, 0, 0 // Position and size
150 ,GetWinHwnd(pParent
) // Owner
152 ,(HMENU
)m_windowId
// Id
153 ,NULL
// Control Data
154 ,NULL
// Presentation Parameters
162 // Subclass again for purposes of dialog editing mode
168 for (lUi
= 0; lUi
< (LONG
)n
; lUi
++)
170 Append(asChoices
[lUi
]);
172 wxFont
* pTextFont
= new wxFont( 10
180 // Set standard wxWindows colors for Listbox items and highlighting
184 vColour
.Set(wxString("WHITE"));
186 LONG lColor
= (LONG
)vColour
.GetPixel();
188 ::WinSetPresParam( m_hWnd
189 ,PP_HILITEFOREGROUNDCOLOR
193 vColour
.Set(wxString("NAVY"));
194 lColor
= (LONG
)vColour
.GetPixel();
195 ::WinSetPresParam( m_hWnd
196 ,PP_HILITEBACKGROUNDCOLOR
208 } // end of wxListBox::Create
210 wxListBox::~wxListBox()
212 #if wxUSE_OWNER_DRAWN
213 size_t lUiCount
= m_aItems
.Count();
215 while (lUiCount
-- != 0)
217 delete m_aItems
[lUiCount
];
219 #endif // wxUSE_OWNER_DRAWN
220 } // end of wxListBox::~wxListBox
222 void wxListBox::SetupColours()
224 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
225 SetForegroundColour(GetParent()->GetForegroundColour());
226 } // end of wxListBox::SetupColours
228 // ----------------------------------------------------------------------------
229 // implementation of wxListBoxBase methods
230 // ----------------------------------------------------------------------------
232 void wxListBox::DoSetFirstItem(
236 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
237 wxT("invalid index in wxListBox::SetFirstItem") );
239 ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX
, MPFROMLONG(N
), (MPARAM
)0);
240 } // end of wxListBox::DoSetFirstItem
242 void wxListBox::Delete(
246 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
247 wxT("invalid index in wxListBox::Delete") );
249 #if wxUSE_OWNER_DRAWN
251 m_aItems
.RemoveAt(N
);
252 #else // !wxUSE_OWNER_DRAWN
253 if (HasClientObjectData())
255 delete GetClientObject(N
);
257 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
259 ::WinSendMsg(GetHwnd(), LM_DELETEITEM
, (MPARAM
)N
, (MPARAM
)0);
261 } // end of wxListBox::DoSetFirstItem
263 int wxListBox::DoAppend(
264 const wxString
& rsItem
268 SHORT nIndexType
= 0;
270 if (m_windowStyle
& wxLB_SORT
)
271 nIndexType
= LIT_SORTASCENDING
;
273 nIndexType
= LIT_END
;
274 nIndex
= (int)::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)nIndexType
, (MPARAM
)rsItem
.c_str());
277 #if wxUSE_OWNER_DRAWN
278 if (m_windowStyle
& wxLB_OWNERDRAW
)
280 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
); // dummy argument
285 pNewItem
->SetName(rsItem
);
286 m_aItems
.Insert(pNewItem
, nIndex
);
287 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, (MPARAM
)((SHORT
)nIndex
), MPFROMP(pNewItem
));
288 pNewItem
->SetFont(GetFont());
292 } // end of wxListBox::DoAppend
294 void wxListBox::DoSetItems(
295 const wxArrayString
& raChoices
296 , void** ppClientData
299 BOOL bHideAndShow
= IsShown();
302 SHORT nIndexType
= 0;
306 ::WinShowWindow(GetHwnd(), FALSE
);
308 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
309 m_nNumItems
= raChoices
.GetCount();
310 for (i
= 0; i
< m_nNumItems
; i
++)
313 if (m_windowStyle
& wxLB_SORT
)
314 nIndexType
= LIT_SORTASCENDING
;
316 nIndexType
= LIT_END
;
317 ::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)nIndexType
, (MPARAM
)raChoices
[i
].c_str());
321 #if wxUSE_OWNER_DRAWN
322 wxASSERT_MSG(ppClientData
[i
] == NULL
,
323 wxT("Can't use client data with owner-drawn listboxes"));
324 #else // !wxUSE_OWNER_DRAWN
325 ::WinSendMsg(WinUtil_GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(lCount
), MPFROMP(ppClientData
[i
]));
326 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
330 #if wxUSE_OWNER_DRAWN
331 if ( m_windowStyle
& wxLB_OWNERDRAW
)
334 // First delete old items
336 WX_CLEAR_ARRAY(m_aItems
);
339 // Then create new ones
341 for (size_t ui
= 0; ui
< (size_t)m_nNumItems
; ui
++)
343 wxOwnerDrawn
* pNewItem
= CreateItem(ui
);
345 pNewItem
->SetName(raChoices
[ui
]);
346 m_aItems
.Add(pNewItem
);
347 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(ui
), MPFROMP(pNewItem
));
350 #endif // wxUSE_OWNER_DRAWN
351 ::WinShowWindow(GetHwnd(), TRUE
);
352 } // end of wxListBox::DoSetItems
354 int wxListBox::FindString(
355 const wxString
& rsString
363 for (nPos
= 0; nPos
< m_nNumItems
; nPos
++)
365 lTextLength
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)nPos
, (MPARAM
)0));
366 zStr
= new char[lTextLength
+ 1];
367 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT(nPos
, (SHORT
)lTextLength
), (MPARAM
)zStr
);
368 if (rsString
== (char*)zStr
)
376 } // end of wxListBox::FindString
378 void wxListBox::Clear()
380 #if wxUSE_OWNER_DRAWN
381 size_t lUiCount
= m_aItems
.Count();
383 while (lUiCount
-- != 0)
385 delete m_aItems
[lUiCount
];
389 #else // !wxUSE_OWNER_DRAWN
390 if (HasClientObjectData())
392 for (size_t n
= 0; n
< (size_t)m_lNumItems
; n
++)
394 delete GetClientObject(n
);
397 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
398 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
401 } // end of wxListBox::Clear
403 void wxListBox::SetSelection(
408 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
409 wxT("invalid index in wxListBox::SetSelection") );
410 ::WinSendMsg( GetHwnd()
415 if(m_windowStyle
& wxLB_OWNERDRAW
)
417 } // end of wxListBox::SetSelection
419 bool wxListBox::IsSelected(
423 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, FALSE
,
424 wxT("invalid index in wxListBox::Selected") );
428 if (GetWindowStyleFlag() & wxLB_EXTENDED
)
431 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
433 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)(N
- 1), (MPARAM
)0));
437 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
439 return (lItem
== (LONG
)N
&& lItem
!= LIT_NONE
);
440 } // end of wxListBox::IsSelected
442 wxClientData
* wxListBox::DoGetItemClientObject(
446 return (wxClientData
*)DoGetItemClientData(n
);
449 void* wxListBox::DoGetItemClientData(
453 wxCHECK_MSG( n
>= 0 && n
< m_nNumItems
, NULL
,
454 wxT("invalid index in wxListBox::GetClientData") );
456 return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE
, MPFROMLONG(n
), (MPARAM
)0));
457 } // end of wxListBox::DoGetItemClientData
459 void wxListBox::DoSetItemClientObject(
461 , wxClientData
* pClientData
464 DoSetItemClientData( n
467 } // end of wxListBox::DoSetItemClientObject
469 void wxListBox::DoSetItemClientData(
474 wxCHECK_RET( n
>= 0 && n
< m_nNumItems
,
475 wxT("invalid index in wxListBox::SetClientData") );
477 #if wxUSE_OWNER_DRAWN
478 if ( m_windowStyle
& wxLB_OWNERDRAW
)
481 // Client data must be pointer to wxOwnerDrawn, otherwise we would crash
482 // in OnMeasure/OnDraw.
484 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
486 #endif // wxUSE_OWNER_DRAWN
488 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(n
), MPFROMP(pClientData
));
489 } // end of wxListBox::DoSetItemClientData
491 bool wxListBox::HasMultipleSelection() const
493 return (m_windowStyle
& wxLB_MULTIPLE
) || (m_windowStyle
& wxLB_EXTENDED
);
494 } // end of wxListBox::HasMultipleSelection
496 int wxListBox::GetSelections(
497 wxArrayInt
& raSelections
504 raSelections
.Empty();
505 if (HasMultipleSelection())
507 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
513 if (lItem
!= LIT_NONE
)
516 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
525 raSelections
.Alloc(nCount
);
526 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
533 raSelections
.Add((int)lItem
);
534 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
541 raSelections
.Add((int)lItem
);
547 else // single-selection listbox
549 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
555 raSelections
.Add((int)lItem
);
559 } // end of wxListBox::GetSelections
561 int wxListBox::GetSelection() const
563 wxCHECK_MSG( !HasMultipleSelection(),
565 wxT("GetSelection() can't be used with multiple-selection "
566 "listboxes, use GetSelections() instead.") );
568 return(LONGFROMMR(::WinSendMsg( GetHwnd()
574 } // end of wxListBox::GetSelection
576 wxString
wxListBox::GetString(
584 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, "",
585 wxT("invalid index in wxListBox::GetClientData") );
587 lLen
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)N
, (MPARAM
)0));
588 zBuf
= new char[lLen
+ 1];
589 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT((SHORT
)N
, (SHORT
)lLen
), (MPARAM
)zBuf
);
594 } // end of wxListBox::GetString
596 void wxListBox::DoInsertItems(
597 const wxArrayString
& asItems
601 wxCHECK_RET( nPos
>= 0 && nPos
<= m_nNumItems
,
602 wxT("invalid index in wxListBox::InsertItems") );
604 int nItems
= asItems
.GetCount();
606 for (int i
= 0; i
< nItems
; i
++)
608 int nIndex
= (int)::WinSendMsg( GetHwnd()
610 ,MPFROMLONG((LONG
)(i
+ nPos
))
611 ,(MPARAM
)asItems
[i
].c_str()
614 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
);
616 pNewItem
->SetName(asItems
[i
]);
617 pNewItem
->SetFont(GetFont());
618 m_aItems
.Insert(pNewItem
, nIndex
);
619 ::WinSendMsg( GetHwnd()
621 ,(MPARAM
)((SHORT
)nIndex
)
624 m_nNumItems
+= nItems
;
626 } // end of wxListBox::DoInsertItems
628 void wxListBox::SetString(
630 , const wxString
& rsString
633 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
634 wxT("invalid index in wxListBox::SetString") );
637 // Remember the state of the item
639 bool bWasSelected
= IsSelected(N
);
640 void* pOldData
= NULL
;
641 wxClientData
* pOldObjData
= NULL
;
643 if (m_clientDataItemsType
== wxClientData_Void
)
644 pOldData
= GetClientData(N
);
645 else if (m_clientDataItemsType
== wxClientData_Object
)
646 pOldObjData
= GetClientObject(N
);
649 // Delete and recreate it
651 ::WinSendMsg( GetHwnd()
659 if (N
== m_nNumItems
- 1)
662 ::WinSendMsg( GetHwnd()
665 ,(MPARAM
)rsString
.c_str()
669 // Restore the client data
675 else if (pOldObjData
)
681 // We may have lost the selection
686 #if wxUSE_OWNER_DRAWN
687 if (m_windowStyle
& wxLB_OWNERDRAW
)
689 // Update item's text
691 m_aItems
[N
]->SetName(rsString
);
692 #endif //USE_OWNER_DRAWN
693 } // end of wxListBox::SetString
695 int wxListBox::GetCount() const
700 // ----------------------------------------------------------------------------
702 // ----------------------------------------------------------------------------
704 wxSize
wxListBox::DoGetBestSize() const
707 // Find the widest string
714 for (int i
= 0; i
< m_nNumItems
; i
++)
716 wxString
vStr(GetString(i
));
722 if (nLine
> nListbox
)
727 // Give it some reasonable default value if there are no strings in the
734 // The listbox should be slightly larger than the widest string
736 wxGetCharSize( GetHWND()
743 int hListbox
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy
) * (wxMax(m_nNumItems
, 7));
745 return wxSize( nListbox
748 } // end of wxListBox::DoGetBestSize
750 // ----------------------------------------------------------------------------
752 // ----------------------------------------------------------------------------
754 bool wxListBox::OS2Command(
756 , WXWORD
WXUNUSED(wId
))
758 wxEventType eEvtType
;
760 if (uParam
== LN_SELECT
)
762 eEvtType
= wxEVT_COMMAND_LISTBOX_SELECTED
;
764 if (uParam
== LN_ENTER
)
766 eEvtType
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
;
771 // Some event we're not interested in
775 wxCommandEvent
vEvent( eEvtType
779 vEvent
.SetEventObject(this);
781 wxArrayInt aSelections
;
783 int nCount
= GetSelections(aSelections
);
788 if (HasClientObjectData())
789 vEvent
.SetClientObject(GetClientObject(n
));
790 else if ( HasClientUntypedData() )
791 vEvent
.SetClientData(GetClientData(n
));
792 vEvent
.SetString(GetString(n
));
798 vEvent
.m_commandInt
= n
;
799 return GetEventHandler()->ProcessEvent(vEvent
);
800 } // end of wxListBox::OS2Command
802 // ----------------------------------------------------------------------------
803 // wxCheckListBox support
804 // ----------------------------------------------------------------------------
806 #if wxUSE_OWNER_DRAWN
812 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
814 long wxListBox::OS2OnMeasure(
815 WXMEASUREITEMSTRUCT
* pItem
819 pItem
= (WXMEASUREITEMSTRUCT
*)new OWNERITEM
;
821 POWNERITEM pMeasureStruct
= (POWNERITEM
)pItem
;
825 // Only owner-drawn control should receive this message
827 wxCHECK( ((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
829 vDc
.SetFont(GetFont());
838 pMeasureStruct
->rclItem
.xRight
= (USHORT
)vWidth
;
839 pMeasureStruct
->rclItem
.xLeft
= 0;
840 pMeasureStruct
->rclItem
.yTop
= 0;
841 pMeasureStruct
->rclItem
.yBottom
= 0;
843 vHeight
= vDc
.GetCharHeight() * 2.5;
844 pMeasureStruct
->rclItem
.yTop
= (USHORT
)vHeight
;
846 return long(MRFROM2SHORT((USHORT
)vHeight
, (USHORT
)vWidth
));
847 } // end of wxListBox::OS2OnMeasure
849 bool wxListBox::OS2OnDraw (
850 WXDRAWITEMSTRUCT
* pItem
853 POWNERITEM pDrawStruct
= (POWNERITEM
)pItem
;
854 LONG lItemID
= pDrawStruct
->idItem
;
859 // Only owner-drawn control should receive this message
861 wxCHECK(((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
865 // The item may be -1 for an empty listbox
870 wxListBoxItem
* pData
= (wxListBoxItem
*)PVOIDFROMMR( ::WinSendMsg( GetHwnd()
872 ,MPFROMLONG(pDrawStruct
->idItem
)
877 wxCHECK(pData
, FALSE
);
880 wxRect
vRect( wxPoint( pDrawStruct
->rclItem
.xLeft
881 ,pDrawStruct
->rclItem
.yTop
883 ,wxPoint( pDrawStruct
->rclItem
.xRight
884 ,pDrawStruct
->rclItem
.yBottom
888 vDc
.SetHPS(pDrawStruct
->hps
);
890 if (pDrawStruct
->fsAttribute
== pDrawStruct
->fsAttributeOld
)
893 // Entire Item needs to be redrawn (either it has reappeared from
894 // behind another window or is being displayed for the first time
896 eAction
= wxOwnerDrawn::wxODDrawAll
;
898 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
901 // If it is currently selected we let the system handle it
903 eStatus
|= wxOwnerDrawn::wxODSelected
;
905 if (pDrawStruct
->fsAttribute
& MIA_CHECKED
)
908 // If it is currently checked we draw our own
910 eStatus
|= wxOwnerDrawn::wxODChecked
;
911 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_CHECKED
;
913 if (pDrawStruct
->fsAttribute
& MIA_DISABLED
)
916 // If it is currently disabled we let the system handle it
918 eStatus
|= wxOwnerDrawn::wxODDisabled
;
921 // Don't really care about framed (indicationg focus) or NoDismiss
926 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
928 eAction
= wxOwnerDrawn::wxODDrawAll
;
929 eStatus
|= wxOwnerDrawn::wxODSelected
;
931 // Keep the system from trying to highlight with its bogus colors
933 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_HILITED
;
935 else if (!(pDrawStruct
->fsAttribute
& MIA_HILITED
))
937 eAction
= wxOwnerDrawn::wxODDrawAll
;
940 // Keep the system from trying to highlight with its bogus colors
942 pDrawStruct
->fsAttribute
= pDrawStruct
->fsAttributeOld
&= ~MIA_HILITED
;
947 // For now we don't care about anything else
948 // just ignore the entire message!
953 return pData
->OnDrawItem( vDc
955 ,(wxOwnerDrawn::wxODAction
)eAction
956 ,(wxOwnerDrawn::wxODStatus
)eStatus
958 } // end of wxListBox::OS2OnDraw
960 #endif // ndef for wxUSE_OWNER_DRAWN
962 #endif // ndef for wxUSE_LISTBOX