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"
30 #include "wx/dynarray.h"
36 #include "wx/ownerdrw.h"
39 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControl
)
41 // ============================================================================
42 // list box item declaration and implementation
43 // ============================================================================
47 class wxListBoxItem
: public wxOwnerDrawn
50 wxListBoxItem(const wxString
& rsStr
= "");
53 wxListBoxItem::wxListBoxItem(
61 // No bitmaps/checkmarks
64 } // end of wxListBoxItem::wxListBoxItem
66 wxOwnerDrawn
* wxListBox::CreateItem(
70 return new wxListBoxItem();
71 } // end of wxListBox::CreateItem
73 #endif //USE_OWNER_DRAWN
75 // ============================================================================
76 // list box control implementation
77 // ============================================================================
80 wxListBox::wxListBox()
84 } // end of wxListBox::wxListBox
86 bool wxListBox::Create(
92 , const wxString asChoices
[]
95 , 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
;
146 // If the parent is a scrolled window the controls must
147 // have this style or they will overlap the scrollbars
150 if (pParent
->IsKindOf(CLASSINFO(wxScrolledWindow
)) ||
151 pParent
->IsKindOf(CLASSINFO(wxGenericScrolledWindow
)))
152 lStyle
|= WS_CLIPSIBLINGS
;
154 m_hWnd
= (WXHWND
)::WinCreateWindow( GetWinHwnd(pParent
) // Parent
155 ,WC_LISTBOX
// Default Listbox class
156 ,"LISTBOX" // Control's name
157 ,lStyle
// Initial Style
158 ,0, 0, 0, 0 // Position and size
159 ,GetWinHwnd(pParent
) // Owner
161 ,(HMENU
)m_windowId
// Id
162 ,NULL
// Control Data
163 ,NULL
// Presentation Parameters
171 // Subclass again for purposes of dialog editing mode
177 for (lUi
= 0; lUi
< (LONG
)n
; lUi
++)
179 Append(asChoices
[lUi
]);
181 SetFont(pParent
->GetFont());
184 // Set standard wxWindows colors for Listbox items and highlighting
188 vColour
.Set(wxString("WHITE"));
190 LONG lColor
= (LONG
)vColour
.GetPixel();
192 ::WinSetPresParam( m_hWnd
193 ,PP_HILITEFOREGROUNDCOLOR
197 vColour
.Set(wxString("NAVY"));
198 lColor
= (LONG
)vColour
.GetPixel();
199 ::WinSetPresParam( m_hWnd
200 ,PP_HILITEBACKGROUNDCOLOR
211 } // end of wxListBox::Create
213 wxListBox::~wxListBox()
215 #if wxUSE_OWNER_DRAWN
216 size_t lUiCount
= m_aItems
.Count();
218 while (lUiCount
-- != 0)
220 delete m_aItems
[lUiCount
];
222 #endif // wxUSE_OWNER_DRAWN
223 } // end of wxListBox::~wxListBox
225 void wxListBox::SetupColours()
227 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW
));
228 SetForegroundColour(GetParent()->GetForegroundColour());
229 } // end of wxListBox::SetupColours
231 // ----------------------------------------------------------------------------
232 // implementation of wxListBoxBase methods
233 // ----------------------------------------------------------------------------
235 void wxListBox::DoSetFirstItem(
239 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
240 wxT("invalid index in wxListBox::SetFirstItem") );
242 ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX
, MPFROMLONG(N
), (MPARAM
)0);
243 } // end of wxListBox::DoSetFirstItem
245 void wxListBox::Delete(
249 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
250 wxT("invalid index in wxListBox::Delete") );
252 #if wxUSE_OWNER_DRAWN
254 m_aItems
.RemoveAt(N
);
255 #else // !wxUSE_OWNER_DRAWN
256 if (HasClientObjectData())
258 delete GetClientObject(N
);
260 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
262 ::WinSendMsg(GetHwnd(), LM_DELETEITEM
, (MPARAM
)N
, (MPARAM
)0);
264 } // end of wxListBox::DoSetFirstItem
266 int wxListBox::DoAppend(
267 const wxString
& rsItem
271 SHORT nIndexType
= 0;
273 if (m_windowStyle
& wxLB_SORT
)
274 nIndexType
= LIT_SORTASCENDING
;
276 nIndexType
= LIT_END
;
277 nIndex
= (int)::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)nIndexType
, (MPARAM
)rsItem
.c_str());
280 #if wxUSE_OWNER_DRAWN
281 if (m_windowStyle
& wxLB_OWNERDRAW
)
283 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
); // dummy argument
285 pNewItem
->SetName(rsItem
);
286 m_aItems
.Add(pNewItem
);
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 size_t lUi
= m_aItems
.Count();
340 delete m_aItems
[lUi
];
345 // Then create new ones
347 for (lUi
= 0; lUi
< (size_t)m_nNumItems
; lUi
++)
349 wxOwnerDrawn
* pNewItem
= CreateItem(lUi
);
351 pNewItem
->SetName(raChoices
[lUi
]);
352 m_aItems
.Add(pNewItem
);
353 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(lUi
), MPFROMP(pNewItem
));
356 #endif // wxUSE_OWNER_DRAWN
357 ::WinShowWindow(GetHwnd(), TRUE
);
358 } // end of wxListBox::DoSetItems
360 int wxListBox::FindString(
361 const wxString
& rsString
369 for (nPos
= 0; nPos
< m_nNumItems
; nPos
++)
371 lTextLength
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)nPos
, (MPARAM
)0));
372 zStr
= new char[lTextLength
+ 1];
373 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT(nPos
, (SHORT
)lTextLength
), (MPARAM
)zStr
);
374 if (rsString
== (char*)zStr
)
382 } // end of wxListBox::FindString
384 void wxListBox::Clear()
386 #if wxUSE_OWNER_DRAWN
387 size_t lUiCount
= m_aItems
.Count();
389 while (lUiCount
-- != 0)
391 delete m_aItems
[lUiCount
];
395 #else // !wxUSE_OWNER_DRAWN
396 if (HasClientObjectData())
398 for (size_t n
= 0; n
< (size_t)m_lNumItems
; n
++)
400 delete GetClientObject(n
);
403 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
404 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
407 } // end of wxListBox::Clear
409 void wxListBox::SetSelection(
414 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
415 wxT("invalid index in wxListBox::SetSelection") );
416 ::WinSendMsg( GetHwnd()
421 } // end of wxListBox::SetSelection
423 bool wxListBox::IsSelected(
427 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, FALSE
,
428 wxT("invalid index in wxListBox::Selected") );
432 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)N
, (MPARAM
)0));
433 return (lItem
!= LIT_NONE
);
434 } // end of wxListBox::IsSelected
436 wxClientData
* wxListBox::DoGetItemClientObject(
440 return (wxClientData
*)DoGetItemClientData(n
);
443 void* wxListBox::DoGetItemClientData(
447 wxCHECK_MSG( n
>= 0 && n
< m_nNumItems
, NULL
,
448 wxT("invalid index in wxListBox::GetClientData") );
450 return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE
, MPFROMLONG(n
), (MPARAM
)0));
451 } // end of wxListBox::DoGetItemClientData
453 void wxListBox::DoSetItemClientObject(
455 , wxClientData
* pClientData
458 DoSetItemClientData( n
461 } // end of wxListBox::DoSetItemClientObject
463 void wxListBox::DoSetItemClientData(
468 wxCHECK_RET( n
>= 0 && n
< m_nNumItems
,
469 wxT("invalid index in wxListBox::SetClientData") );
471 #if wxUSE_OWNER_DRAWN
472 if ( m_windowStyle
& wxLB_OWNERDRAW
)
475 // Client data must be pointer to wxOwnerDrawn, otherwise we would crash
476 // in OnMeasure/OnDraw.
478 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
480 #endif // wxUSE_OWNER_DRAWN
482 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(n
), MPFROMP(pClientData
));
483 } // end of wxListBox::DoSetItemClientData
485 bool wxListBox::HasMultipleSelection() const
487 return (m_windowStyle
& wxLB_MULTIPLE
) || (m_windowStyle
& wxLB_EXTENDED
);
488 } // end of wxListBox::HasMultipleSelection
490 int wxListBox::GetSelections(
491 wxArrayInt
& raSelections
498 raSelections
.Empty();
499 if (HasMultipleSelection())
501 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
507 if (lItem
!= LIT_NONE
)
510 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
519 raSelections
.Alloc(nCount
);
520 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
527 raSelections
.Add((int)lItem
);
528 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
535 raSelections
.Add((int)lItem
);
541 else // single-selection listbox
543 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
549 raSelections
.Add((int)lItem
);
553 } // end of wxListBox::GetSelections
555 int wxListBox::GetSelection() const
557 wxCHECK_MSG( !HasMultipleSelection(),
559 wxT("GetSelection() can't be used with multiple-selection "
560 "listboxes, use GetSelections() instead.") );
562 return(LONGFROMMR(::WinSendMsg( GetHwnd()
568 } // end of wxListBox::GetSelection
570 wxString
wxListBox::GetString(
578 wxCHECK_MSG( N
>= 0 && N
< m_nNumItems
, "",
579 wxT("invalid index in wxListBox::GetClientData") );
581 lLen
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)N
, (MPARAM
)0));
582 zBuf
= new char[lLen
+ 1];
583 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT((SHORT
)N
, (SHORT
)lLen
), (MPARAM
)zBuf
);
588 } // end of wxListBox::GetString
590 void wxListBox::DoInsertItems(
591 const wxArrayString
& asItems
595 wxCHECK_RET( nPos
>= 0 && nPos
<= m_nNumItems
,
596 wxT("invalid index in wxListBox::InsertItems") );
598 int nItems
= asItems
.GetCount();
600 for (int i
= 0; i
< nItems
; i
++)
601 ::WinSendMsg(GetHwnd(), LM_INSERTITEM
, MPFROMLONG((LONG
)(i
+ nPos
)), (MPARAM
)asItems
[i
].c_str());
602 m_nNumItems
+= nItems
;
603 } // end of wxListBox::DoInsertItems
605 void wxListBox::SetString(
607 , const wxString
& rsString
610 wxCHECK_RET( N
>= 0 && N
< m_nNumItems
,
611 wxT("invalid index in wxListBox::SetString") );
614 // Remember the state of the item
616 bool bWasSelected
= IsSelected(N
);
617 void* pOldData
= NULL
;
618 wxClientData
* pOldObjData
= NULL
;
620 if (m_clientDataItemsType
== wxClientData_Void
)
621 pOldData
= GetClientData(N
);
622 else if (m_clientDataItemsType
== wxClientData_Object
)
623 pOldObjData
= GetClientObject(N
);
626 // Delete and recreate it
628 ::WinSendMsg( GetHwnd()
636 if (N
== m_nNumItems
- 1)
639 ::WinSendMsg( GetHwnd()
642 ,(MPARAM
)rsString
.c_str()
646 // Restore the client data
652 else if (pOldObjData
)
658 // We may have lost the selection
663 #if wxUSE_OWNER_DRAWN
664 if (m_windowStyle
& wxLB_OWNERDRAW
)
666 // Update item's text
668 m_aItems
[N
]->SetName(rsString
);
669 #endif //USE_OWNER_DRAWN
670 } // end of wxListBox::SetString
672 int wxListBox::GetCount() const
677 // ----------------------------------------------------------------------------
679 // ----------------------------------------------------------------------------
681 wxSize
wxListBox::DoGetBestSize() const
684 // Find the widest string
691 for (int i
= 0; i
< m_nNumItems
; i
++)
693 wxString
vStr(GetString(i
));
699 if (nLine
> nListbox
)
704 // Give it some reasonable default value if there are no strings in the
711 // The listbox should be slightly larger than the widest string
713 wxGetCharSize( GetHWND()
720 int hListbox
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy
) * (wxMax(m_nNumItems
, 7));
722 return wxSize( nListbox
725 } // end of wxListBox::DoGetBestSize
727 // ----------------------------------------------------------------------------
729 // ----------------------------------------------------------------------------
731 bool wxListBox::OS2Command(
733 , WXWORD
WXUNUSED(wId
))
735 wxEventType eEvtType
;
737 if (uParam
== LN_SELECT
)
739 eEvtType
= wxEVT_COMMAND_LISTBOX_SELECTED
;
741 if (uParam
== LN_ENTER
)
743 eEvtType
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
;
748 // Some event we're not interested in
752 wxCommandEvent
vEvent( eEvtType
756 vEvent
.SetEventObject(this);
758 wxArrayInt aSelections
;
760 int nCount
= GetSelections(aSelections
);
765 if (HasClientObjectData())
766 vEvent
.SetClientObject(GetClientObject(n
));
767 else if ( HasClientUntypedData() )
768 vEvent
.SetClientData(GetClientData(n
));
769 vEvent
.SetString(GetString(n
));
775 vEvent
.m_commandInt
= n
;
776 return GetEventHandler()->ProcessEvent(vEvent
);
777 } // end of wxListBox::OS2Command
779 // ----------------------------------------------------------------------------
780 // wxCheckListBox support
781 // ----------------------------------------------------------------------------
783 #if wxUSE_OWNER_DRAWN
789 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
791 bool wxListBox::OS2OnMeasure(WXMEASUREITEMSTRUCT
*item
)
794 // TODO: Get to this eventually
799 bool wxListBox::OS2OnDraw(WXDRAWITEMSTRUCT
*item
)
802 // TODO: Get to this eventually
806 #endif // ndef for wxUSE_OWNER_DRAWN
808 #endif // ndef for wxUSE_LISTBOX