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
286 pNewItem
->SetName(rsItem
);
287 m_aItems
.Insert(pNewItem
, nIndex
);
288 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, (MPARAM
)((SHORT
)nIndex
), MPFROMP(pNewItem
));
289 pNewItem
->SetFont(GetFont());
293 } // end of wxListBox::DoAppend
295 void wxListBox::DoSetItems(
296 const wxArrayString
& raChoices
297 , void** ppClientData
300 BOOL bHideAndShow
= IsShown();
303 SHORT nIndexType
= 0;
307 ::WinShowWindow(GetHwnd(), FALSE
);
309 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
310 m_nNumItems
= raChoices
.GetCount();
311 for (i
= 0; i
< m_nNumItems
; i
++)
314 if (m_windowStyle
& wxLB_SORT
)
315 nIndexType
= LIT_SORTASCENDING
;
317 nIndexType
= LIT_END
;
318 ::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)nIndexType
, (MPARAM
)raChoices
[i
].c_str());
322 #if wxUSE_OWNER_DRAWN
323 wxASSERT_MSG(ppClientData
[i
] == NULL
,
324 wxT("Can't use client data with owner-drawn listboxes"));
325 #else // !wxUSE_OWNER_DRAWN
326 ::WinSendMsg(WinUtil_GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(lCount
), MPFROMP(ppClientData
[i
]));
327 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
331 #if wxUSE_OWNER_DRAWN
332 if ( m_windowStyle
& wxLB_OWNERDRAW
)
335 // First delete old items
337 WX_CLEAR_ARRAY(m_aItems
);
340 // Then create new ones
342 for (size_t ui
= 0; ui
< (size_t)m_nNumItems
; ui
++)
344 wxOwnerDrawn
* pNewItem
= CreateItem(ui
);
346 pNewItem
->SetName(raChoices
[ui
]);
347 m_aItems
.Add(pNewItem
);
348 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(ui
), MPFROMP(pNewItem
));
351 #endif // wxUSE_OWNER_DRAWN
352 ::WinShowWindow(GetHwnd(), TRUE
);
353 } // end of wxListBox::DoSetItems
355 int wxListBox::FindString(
356 const wxString
& rsString
364 for (nPos
= 0; nPos
< m_nNumItems
; nPos
++)
366 lTextLength
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)nPos
, (MPARAM
)0));
367 zStr
= new char[lTextLength
+ 1];
368 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT(nPos
, (SHORT
)lTextLength
), (MPARAM
)zStr
);
369 if (rsString
== (char*)zStr
)
377 } // end of wxListBox::FindString
379 void wxListBox::Clear()
381 #if wxUSE_OWNER_DRAWN
382 size_t lUiCount
= m_aItems
.Count();
384 while (lUiCount
-- != 0)
386 delete m_aItems
[lUiCount
];
390 #else // !wxUSE_OWNER_DRAWN
391 if (HasClientObjectData())
393 for (size_t n
= 0; n
< (size_t)m_lNumItems
; n
++)
395 delete GetClientObject(n
);
398 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
399 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
402 } // end of wxListBox::Clear
404 void wxListBox::SetSelection(
409 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
410 wxT("invalid index in wxListBox::SetSelection") );
411 ::WinSendMsg( GetHwnd()
416 if(m_windowStyle
& wxLB_OWNERDRAW
)
418 } // end of wxListBox::SetSelection
420 bool wxListBox::IsSelected(
424 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, FALSE
,
425 wxT("invalid index in wxListBox::Selected") );
429 if (GetWindowStyleFlag() & wxLB_EXTENDED
)
432 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
434 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)(N
- 1), (MPARAM
)0));
438 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
440 return (lItem
== (LONG
)N
&& lItem
!= LIT_NONE
);
441 } // end of wxListBox::IsSelected
443 wxClientData
* wxListBox::DoGetItemClientObject(
447 return (wxClientData
*)DoGetItemClientData(n
);
450 void* wxListBox::DoGetItemClientData(
454 wxCHECK_MSG( n
>= 0 && n
< m_nNumItems
, NULL
,
455 wxT("invalid index in wxListBox::GetClientData") );
457 return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE
, MPFROMLONG(n
), (MPARAM
)0));
458 } // end of wxListBox::DoGetItemClientData
460 void wxListBox::DoSetItemClientObject(
462 , wxClientData
* pClientData
465 DoSetItemClientData( n
468 } // end of wxListBox::DoSetItemClientObject
470 void wxListBox::DoSetItemClientData(
475 wxCHECK_RET( n
>= 0 && n
< m_nNumItems
,
476 wxT("invalid index in wxListBox::SetClientData") );
478 #if wxUSE_OWNER_DRAWN
479 if ( m_windowStyle
& wxLB_OWNERDRAW
)
482 // Client data must be pointer to wxOwnerDrawn, otherwise we would crash
483 // in OnMeasure/OnDraw.
485 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
487 #endif // wxUSE_OWNER_DRAWN
489 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(n
), MPFROMP(pClientData
));
490 } // end of wxListBox::DoSetItemClientData
492 bool wxListBox::HasMultipleSelection() const
494 return (m_windowStyle
& wxLB_MULTIPLE
) || (m_windowStyle
& wxLB_EXTENDED
);
495 } // end of wxListBox::HasMultipleSelection
497 int wxListBox::GetSelections(
498 wxArrayInt
& raSelections
505 raSelections
.Empty();
506 if (HasMultipleSelection())
508 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
514 if (lItem
!= LIT_NONE
)
517 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
526 raSelections
.Alloc(nCount
);
527 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
534 raSelections
.Add((int)lItem
);
535 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
542 raSelections
.Add((int)lItem
);
548 else // single-selection listbox
550 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
556 raSelections
.Add((int)lItem
);
560 } // end of wxListBox::GetSelections
562 int wxListBox::GetSelection() const
564 wxCHECK_MSG( !HasMultipleSelection(),
566 wxT("GetSelection() can't be used with multiple-selection "
567 "listboxes, use GetSelections() instead.") );
569 return(LONGFROMMR(::WinSendMsg( GetHwnd()
575 } // end of wxListBox::GetSelection
577 wxString
wxListBox::GetString(
585 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, "",
586 wxT("invalid index in wxListBox::GetClientData") );
588 lLen
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)N
, (MPARAM
)0));
589 zBuf
= new char[lLen
+ 1];
590 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT((SHORT
)N
, (SHORT
)lLen
), (MPARAM
)zBuf
);
595 } // end of wxListBox::GetString
597 void wxListBox::DoInsertItems(
598 const wxArrayString
& asItems
602 wxCHECK_RET( nPos
>= 0 && nPos
<= m_nNumItems
,
603 wxT("invalid index in wxListBox::InsertItems") );
605 int nItems
= asItems
.GetCount();
607 for (int i
= 0; i
< nItems
; i
++)
609 int nIndex
= (int)::WinSendMsg( GetHwnd()
611 ,MPFROMLONG((LONG
)(i
+ nPos
))
612 ,(MPARAM
)asItems
[i
].c_str()
615 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
);
617 pNewItem
->SetName(asItems
[i
]);
618 pNewItem
->SetFont(GetFont());
619 m_aItems
.Insert(pNewItem
, nIndex
);
620 ::WinSendMsg( GetHwnd()
622 ,(MPARAM
)((SHORT
)nIndex
)
625 m_nNumItems
+= nItems
;
627 } // end of wxListBox::DoInsertItems
629 void wxListBox::SetString(
631 , const wxString
& rsString
634 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
635 wxT("invalid index in wxListBox::SetString") );
638 // Remember the state of the item
640 bool bWasSelected
= IsSelected(N
);
641 void* pOldData
= NULL
;
642 wxClientData
* pOldObjData
= NULL
;
644 if (m_clientDataItemsType
== wxClientData_Void
)
645 pOldData
= GetClientData(N
);
646 else if (m_clientDataItemsType
== wxClientData_Object
)
647 pOldObjData
= GetClientObject(N
);
650 // Delete and recreate it
652 ::WinSendMsg( GetHwnd()
660 if (N
== m_nNumItems
- 1)
663 ::WinSendMsg( GetHwnd()
666 ,(MPARAM
)rsString
.c_str()
670 // Restore the client data
676 else if (pOldObjData
)
682 // We may have lost the selection
687 #if wxUSE_OWNER_DRAWN
688 if (m_windowStyle
& wxLB_OWNERDRAW
)
690 // Update item's text
692 m_aItems
[N
]->SetName(rsString
);
693 #endif //USE_OWNER_DRAWN
694 } // end of wxListBox::SetString
696 int wxListBox::GetCount() const
701 // ----------------------------------------------------------------------------
703 // ----------------------------------------------------------------------------
705 wxSize
wxListBox::DoGetBestSize() const
708 // Find the widest string
715 for (int i
= 0; i
< m_nNumItems
; i
++)
717 wxString
vStr(GetString(i
));
723 if (nLine
> nListbox
)
728 // Give it some reasonable default value if there are no strings in the
735 // The listbox should be slightly larger than the widest string
737 wxGetCharSize( GetHWND()
744 int hListbox
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy
) * (wxMax(m_nNumItems
, 7));
746 return wxSize( nListbox
749 } // end of wxListBox::DoGetBestSize
751 // ----------------------------------------------------------------------------
753 // ----------------------------------------------------------------------------
755 bool wxListBox::OS2Command(
757 , WXWORD
WXUNUSED(wId
))
759 wxEventType eEvtType
;
761 if (uParam
== LN_SELECT
)
763 eEvtType
= wxEVT_COMMAND_LISTBOX_SELECTED
;
765 if (uParam
== LN_ENTER
)
767 eEvtType
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
;
772 // Some event we're not interested in
776 wxCommandEvent
vEvent( eEvtType
780 vEvent
.SetEventObject(this);
782 wxArrayInt aSelections
;
784 int nCount
= GetSelections(aSelections
);
789 if (HasClientObjectData())
790 vEvent
.SetClientObject(GetClientObject(n
));
791 else if ( HasClientUntypedData() )
792 vEvent
.SetClientData(GetClientData(n
));
793 vEvent
.SetString(GetString(n
));
799 vEvent
.m_commandInt
= n
;
800 return GetEventHandler()->ProcessEvent(vEvent
);
801 } // end of wxListBox::OS2Command
803 // ----------------------------------------------------------------------------
804 // wxCheckListBox support
805 // ----------------------------------------------------------------------------
807 #if wxUSE_OWNER_DRAWN
813 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
815 long wxListBox::OS2OnMeasure(
816 WXMEASUREITEMSTRUCT
* pItem
820 pItem
= (WXMEASUREITEMSTRUCT
*)new OWNERITEM
;
822 POWNERITEM pMeasureStruct
= (POWNERITEM
)pItem
;
826 // Only owner-drawn control should receive this message
828 wxCHECK( ((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
830 vDc
.SetFont(GetFont());
839 pMeasureStruct
->rclItem
.xRight
= (USHORT
)vWidth
;
840 pMeasureStruct
->rclItem
.xLeft
= 0;
841 pMeasureStruct
->rclItem
.yTop
= 0;
842 pMeasureStruct
->rclItem
.yBottom
= 0;
844 vHeight
= vDc
.GetCharHeight() * 2.5;
845 pMeasureStruct
->rclItem
.yTop
= (USHORT
)vHeight
;
847 return long(MRFROM2SHORT((USHORT
)vHeight
, (USHORT
)vWidth
));
848 } // end of wxListBox::OS2OnMeasure
850 bool wxListBox::OS2OnDraw (
851 WXDRAWITEMSTRUCT
* pItem
854 POWNERITEM pDrawStruct
= (POWNERITEM
)pItem
;
855 LONG lItemID
= pDrawStruct
->idItem
;
860 // Only owner-drawn control should receive this message
862 wxCHECK(((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
866 // The item may be -1 for an empty listbox
871 wxListBoxItem
* pData
= (wxListBoxItem
*)PVOIDFROMMR( ::WinSendMsg( GetHwnd()
873 ,MPFROMLONG(pDrawStruct
->idItem
)
878 wxCHECK(pData
, FALSE
);
881 wxRect
vRect( wxPoint( pDrawStruct
->rclItem
.xLeft
882 ,pDrawStruct
->rclItem
.yTop
884 ,wxPoint( pDrawStruct
->rclItem
.xRight
885 ,pDrawStruct
->rclItem
.yBottom
889 vDc
.SetHPS(pDrawStruct
->hps
);
891 if (pDrawStruct
->fsAttribute
== pDrawStruct
->fsAttributeOld
)
894 // Entire Item needs to be redrawn (either it has reappeared from
895 // behind another window or is being displayed for the first time
897 eAction
= wxOwnerDrawn::wxODDrawAll
;
899 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
902 // If it is currently selected we let the system handle it
904 eStatus
|= wxOwnerDrawn::wxODSelected
;
906 if (pDrawStruct
->fsAttribute
& MIA_CHECKED
)
909 // If it is currently checked we draw our own
911 eStatus
|= wxOwnerDrawn::wxODChecked
;
912 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_CHECKED
;
914 if (pDrawStruct
->fsAttribute
& MIA_DISABLED
)
917 // If it is currently disabled we let the system handle it
919 eStatus
|= wxOwnerDrawn::wxODDisabled
;
922 // Don't really care about framed (indicationg focus) or NoDismiss
927 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
929 eAction
= wxOwnerDrawn::wxODDrawAll
;
930 eStatus
|= wxOwnerDrawn::wxODSelected
;
932 // Keep the system from trying to highlight with its bogus colors
934 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_HILITED
;
936 else if (!(pDrawStruct
->fsAttribute
& MIA_HILITED
))
938 eAction
= wxOwnerDrawn::wxODDrawAll
;
941 // Keep the system from trying to highlight with its bogus colors
943 pDrawStruct
->fsAttribute
= pDrawStruct
->fsAttributeOld
&= ~MIA_HILITED
;
948 // For now we don't care about anything else
949 // just ignore the entire message!
954 return pData
->OnDrawItem( vDc
956 ,(wxOwnerDrawn::wxODAction
)eAction
957 ,(wxOwnerDrawn::wxODStatus
)eStatus
959 } // end of wxListBox::OS2OnDraw
961 #endif // ndef for wxUSE_OWNER_DRAWN
963 #endif // ndef for wxUSE_LISTBOX