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
;
147 // If the parent is a scrolled window the controls must
148 // have this style or they will overlap the scrollbars
151 if (pParent
->IsKindOf(CLASSINFO(wxScrolledWindow
)) ||
152 pParent
->IsKindOf(CLASSINFO(wxGenericScrolledWindow
)))
153 lStyle
|= WS_CLIPSIBLINGS
;
155 m_hWnd
= (WXHWND
)::WinCreateWindow( GetWinHwnd(pParent
) // Parent
156 ,WC_LISTBOX
// Default Listbox class
157 ,"LISTBOX" // Control's name
158 ,lStyle
// Initial Style
159 ,0, 0, 0, 0 // Position and size
160 ,GetWinHwnd(pParent
) // Owner
162 ,(HMENU
)m_windowId
// Id
163 ,NULL
// Control Data
164 ,NULL
// Presentation Parameters
172 // Subclass again for purposes of dialog editing mode
178 for (lUi
= 0; lUi
< (LONG
)n
; lUi
++)
180 Append(asChoices
[lUi
]);
182 SetFont(*wxSMALL_FONT
);
185 // Set standard wxWindows colors for Listbox items and highlighting
189 vColour
.Set(wxString("WHITE"));
191 LONG lColor
= (LONG
)vColour
.GetPixel();
193 ::WinSetPresParam( m_hWnd
194 ,PP_HILITEFOREGROUNDCOLOR
198 vColour
.Set(wxString("NAVY"));
199 lColor
= (LONG
)vColour
.GetPixel();
200 ::WinSetPresParam( m_hWnd
201 ,PP_HILITEBACKGROUNDCOLOR
212 } // end of wxListBox::Create
214 wxListBox::~wxListBox()
216 #if wxUSE_OWNER_DRAWN
217 size_t lUiCount
= m_aItems
.Count();
219 while (lUiCount
-- != 0)
221 delete m_aItems
[lUiCount
];
223 #endif // wxUSE_OWNER_DRAWN
224 } // end of wxListBox::~wxListBox
226 void wxListBox::SetupColours()
228 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
229 SetForegroundColour(GetParent()->GetForegroundColour());
230 } // end of wxListBox::SetupColours
232 // ----------------------------------------------------------------------------
233 // implementation of wxListBoxBase methods
234 // ----------------------------------------------------------------------------
236 void wxListBox::DoSetFirstItem(
240 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
241 wxT("invalid index in wxListBox::SetFirstItem") );
243 ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX
, MPFROMLONG(N
), (MPARAM
)0);
244 } // end of wxListBox::DoSetFirstItem
246 void wxListBox::Delete(
250 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
251 wxT("invalid index in wxListBox::Delete") );
253 #if wxUSE_OWNER_DRAWN
255 m_aItems
.RemoveAt(N
);
256 #else // !wxUSE_OWNER_DRAWN
257 if (HasClientObjectData())
259 delete GetClientObject(N
);
261 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
263 ::WinSendMsg(GetHwnd(), LM_DELETEITEM
, (MPARAM
)N
, (MPARAM
)0);
265 } // end of wxListBox::DoSetFirstItem
267 int wxListBox::DoAppend(
268 const wxString
& rsItem
272 SHORT nIndexType
= 0;
274 if (m_windowStyle
& wxLB_SORT
)
275 nIndexType
= LIT_SORTASCENDING
;
277 nIndexType
= LIT_END
;
278 nIndex
= (int)::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)nIndexType
, (MPARAM
)rsItem
.c_str());
281 #if wxUSE_OWNER_DRAWN
282 if (m_windowStyle
& wxLB_OWNERDRAW
)
284 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
); // dummy argument
286 pNewItem
->SetName(rsItem
);
287 m_aItems
.Add(pNewItem
);
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 size_t lUi
= m_aItems
.Count();
341 delete m_aItems
[lUi
];
346 // Then create new ones
348 for (lUi
= 0; lUi
< (size_t)m_nNumItems
; lUi
++)
350 wxOwnerDrawn
* pNewItem
= CreateItem(lUi
);
352 pNewItem
->SetName(raChoices
[lUi
]);
353 m_aItems
.Add(pNewItem
);
354 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(lUi
), MPFROMP(pNewItem
));
357 #endif // wxUSE_OWNER_DRAWN
358 ::WinShowWindow(GetHwnd(), TRUE
);
359 } // end of wxListBox::DoSetItems
361 int wxListBox::FindString(
362 const wxString
& rsString
370 for (nPos
= 0; nPos
< m_nNumItems
; nPos
++)
372 lTextLength
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)nPos
, (MPARAM
)0));
373 zStr
= new char[lTextLength
+ 1];
374 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT(nPos
, (SHORT
)lTextLength
), (MPARAM
)zStr
);
375 if (rsString
== (char*)zStr
)
383 } // end of wxListBox::FindString
385 void wxListBox::Clear()
387 #if wxUSE_OWNER_DRAWN
388 size_t lUiCount
= m_aItems
.Count();
390 while (lUiCount
-- != 0)
392 delete m_aItems
[lUiCount
];
396 #else // !wxUSE_OWNER_DRAWN
397 if (HasClientObjectData())
399 for (size_t n
= 0; n
< (size_t)m_lNumItems
; n
++)
401 delete GetClientObject(n
);
404 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
405 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
408 } // end of wxListBox::Clear
410 void wxListBox::SetSelection(
415 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
416 wxT("invalid index in wxListBox::SetSelection") );
417 ::WinSendMsg( GetHwnd()
422 } // end of wxListBox::SetSelection
424 bool wxListBox::IsSelected(
428 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, FALSE
,
429 wxT("invalid index in wxListBox::Selected") );
433 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)N
, (MPARAM
)0));
434 return (lItem
!= LIT_NONE
);
435 } // end of wxListBox::IsSelected
437 wxClientData
* wxListBox::DoGetItemClientObject(
441 return (wxClientData
*)DoGetItemClientData(n
);
444 void* wxListBox::DoGetItemClientData(
448 wxCHECK_MSG( n
>= 0 && n
< m_nNumItems
, NULL
,
449 wxT("invalid index in wxListBox::GetClientData") );
451 return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE
, MPFROMLONG(n
), (MPARAM
)0));
452 } // end of wxListBox::DoGetItemClientData
454 void wxListBox::DoSetItemClientObject(
456 , wxClientData
* pClientData
459 DoSetItemClientData( n
462 } // end of wxListBox::DoSetItemClientObject
464 void wxListBox::DoSetItemClientData(
469 wxCHECK_RET( n
>= 0 && n
< m_nNumItems
,
470 wxT("invalid index in wxListBox::SetClientData") );
472 #if wxUSE_OWNER_DRAWN
473 if ( m_windowStyle
& wxLB_OWNERDRAW
)
476 // Client data must be pointer to wxOwnerDrawn, otherwise we would crash
477 // in OnMeasure/OnDraw.
479 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
481 #endif // wxUSE_OWNER_DRAWN
483 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(n
), MPFROMP(pClientData
));
484 } // end of wxListBox::DoSetItemClientData
486 bool wxListBox::HasMultipleSelection() const
488 return (m_windowStyle
& wxLB_MULTIPLE
) || (m_windowStyle
& wxLB_EXTENDED
);
489 } // end of wxListBox::HasMultipleSelection
491 int wxListBox::GetSelections(
492 wxArrayInt
& raSelections
499 raSelections
.Empty();
500 if (HasMultipleSelection())
502 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
508 if (lItem
!= LIT_NONE
)
511 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
520 raSelections
.Alloc(nCount
);
521 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
528 raSelections
.Add((int)lItem
);
529 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
536 raSelections
.Add((int)lItem
);
542 else // single-selection listbox
544 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
550 raSelections
.Add((int)lItem
);
554 } // end of wxListBox::GetSelections
556 int wxListBox::GetSelection() const
558 wxCHECK_MSG( !HasMultipleSelection(),
560 wxT("GetSelection() can't be used with multiple-selection "
561 "listboxes, use GetSelections() instead.") );
563 return(LONGFROMMR(::WinSendMsg( GetHwnd()
569 } // end of wxListBox::GetSelection
571 wxString
wxListBox::GetString(
579 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, "",
580 wxT("invalid index in wxListBox::GetClientData") );
582 lLen
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)N
, (MPARAM
)0));
583 zBuf
= new char[lLen
+ 1];
584 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT((SHORT
)N
, (SHORT
)lLen
), (MPARAM
)zBuf
);
589 } // end of wxListBox::GetString
591 void wxListBox::DoInsertItems(
592 const wxArrayString
& asItems
596 wxCHECK_RET( nPos
>= 0 && nPos
<= m_nNumItems
,
597 wxT("invalid index in wxListBox::InsertItems") );
599 int nItems
= asItems
.GetCount();
601 for (int i
= 0; i
< nItems
; i
++)
602 ::WinSendMsg(GetHwnd(), LM_INSERTITEM
, MPFROMLONG((LONG
)(i
+ nPos
)), (MPARAM
)asItems
[i
].c_str());
603 m_nNumItems
+= nItems
;
604 } // end of wxListBox::DoInsertItems
606 void wxListBox::SetString(
608 , const wxString
& rsString
611 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
612 wxT("invalid index in wxListBox::SetString") );
615 // Remember the state of the item
617 bool bWasSelected
= IsSelected(N
);
618 void* pOldData
= NULL
;
619 wxClientData
* pOldObjData
= NULL
;
621 if (m_clientDataItemsType
== wxClientData_Void
)
622 pOldData
= GetClientData(N
);
623 else if (m_clientDataItemsType
== wxClientData_Object
)
624 pOldObjData
= GetClientObject(N
);
627 // Delete and recreate it
629 ::WinSendMsg( GetHwnd()
637 if (N
== m_nNumItems
- 1)
640 ::WinSendMsg( GetHwnd()
643 ,(MPARAM
)rsString
.c_str()
647 // Restore the client data
653 else if (pOldObjData
)
659 // We may have lost the selection
664 #if wxUSE_OWNER_DRAWN
665 if (m_windowStyle
& wxLB_OWNERDRAW
)
667 // Update item's text
669 m_aItems
[N
]->SetName(rsString
);
670 #endif //USE_OWNER_DRAWN
671 } // end of wxListBox::SetString
673 int wxListBox::GetCount() const
678 // ----------------------------------------------------------------------------
680 // ----------------------------------------------------------------------------
682 wxSize
wxListBox::DoGetBestSize() const
685 // Find the widest string
692 for (int i
= 0; i
< m_nNumItems
; i
++)
694 wxString
vStr(GetString(i
));
700 if (nLine
> nListbox
)
705 // Give it some reasonable default value if there are no strings in the
712 // The listbox should be slightly larger than the widest string
714 wxGetCharSize( GetHWND()
721 int hListbox
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy
) * (wxMax(m_nNumItems
, 7));
723 return wxSize( nListbox
726 } // end of wxListBox::DoGetBestSize
728 // ----------------------------------------------------------------------------
730 // ----------------------------------------------------------------------------
732 bool wxListBox::OS2Command(
734 , WXWORD
WXUNUSED(wId
))
736 wxEventType eEvtType
;
738 if (uParam
== LN_SELECT
)
740 eEvtType
= wxEVT_COMMAND_LISTBOX_SELECTED
;
742 if (uParam
== LN_ENTER
)
744 eEvtType
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
;
749 // Some event we're not interested in
753 wxCommandEvent
vEvent( eEvtType
757 vEvent
.SetEventObject(this);
759 wxArrayInt aSelections
;
761 int nCount
= GetSelections(aSelections
);
766 if (HasClientObjectData())
767 vEvent
.SetClientObject(GetClientObject(n
));
768 else if ( HasClientUntypedData() )
769 vEvent
.SetClientData(GetClientData(n
));
770 vEvent
.SetString(GetString(n
));
776 vEvent
.m_commandInt
= n
;
777 return GetEventHandler()->ProcessEvent(vEvent
);
778 } // end of wxListBox::OS2Command
780 // ----------------------------------------------------------------------------
781 // wxCheckListBox support
782 // ----------------------------------------------------------------------------
784 #if wxUSE_OWNER_DRAWN
790 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
792 bool wxListBox::OS2OnMeasure(WXMEASUREITEMSTRUCT
*item
)
795 // TODO: Get to this eventually
800 bool wxListBox::OS2OnDraw(WXDRAWITEMSTRUCT
*item
)
803 // TODO: Get to this eventually
807 #endif // ndef for wxUSE_OWNER_DRAWN
809 #endif // ndef for wxUSE_LISTBOX