1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/os2/listbox.cpp
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"
17 #include "wx/window.h"
18 #include "wx/os2/private.h"
21 #include "wx/listbox.h"
22 #include "wx/settings.h"
26 #include "wx/dcscreen.h"
28 #include "wx/scrolwin.h"
34 #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
= wxEmptyString
);
55 wxListBoxItem::wxListBoxItem(
63 // No bitmaps/checkmarks
66 } // end of wxListBoxItem::wxListBoxItem
68 wxOwnerDrawn
* wxListBox::CreateItem( size_t WXUNUSED(n
) )
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(
91 , const wxArrayString
& asChoices
93 , const wxValidator
& rValidator
94 , const wxString
& rsName
97 wxCArrayString
chs(asChoices
);
99 return Create(pParent
, vId
, rPos
, rSize
, chs
.GetCount(), chs
.GetStrings(),
100 lStyle
, rValidator
, rsName
);
103 bool wxListBox::Create( wxWindow
* pParent
,
108 const wxString asChoices
[],
110 const wxValidator
& rValidator
,
111 const wxString
& rsName
)
119 SetValidator(rValidator
);
123 pParent
->AddChild(this);
125 wxSystemSettings vSettings
;
127 SetBackgroundColour(vSettings
.GetColour(wxSYS_COLOUR_WINDOW
));
128 SetForegroundColour(pParent
->GetForegroundColour());
130 m_windowId
= (vId
== -1) ? (int)NewControlId() : vId
;
134 int nWidth
= rSize
.x
;
135 int nHeight
= rSize
.y
;
137 m_windowStyle
= lStyle
;
141 if (m_windowStyle
& wxCLIP_SIBLINGS
)
142 lStyle
|= WS_CLIPSIBLINGS
;
143 if (m_windowStyle
& wxLB_MULTIPLE
)
144 lStyle
|= LS_MULTIPLESEL
;
145 else if (m_windowStyle
& wxLB_EXTENDED
)
146 lStyle
|= LS_EXTENDEDSEL
;
147 if (m_windowStyle
& wxLB_HSCROLL
)
148 lStyle
|= LS_HORZSCROLL
;
149 if (m_windowStyle
& wxLB_OWNERDRAW
)
150 lStyle
|= LS_OWNERDRAW
;
153 // Without this style, you get unexpected heights, so e.g. constraint layout
154 // doesn't work properly
156 lStyle
|= LS_NOADJUSTPOS
;
158 m_hWnd
= (WXHWND
)::WinCreateWindow( GetWinHwnd(pParent
) // Parent
159 ,WC_LISTBOX
// Default Listbox class
160 ,"LISTBOX" // Control's name
161 ,lStyle
// Initial Style
162 ,0, 0, 0, 0 // Position and size
163 ,GetWinHwnd(pParent
) // Owner
165 ,(HMENU
)m_windowId
// Id
166 ,NULL
// Control Data
167 ,NULL
// Presentation Parameters
175 // Subclass again for purposes of dialog editing mode
181 for (lUi
= 0; lUi
< (LONG
)n
; lUi
++)
183 Append(asChoices
[lUi
]);
185 wxFont
* pTextFont
= new wxFont( 10
193 // Set OS/2 system colours for Listbox items and highlighting
197 vColour
= wxSystemSettingsNative::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
);
199 LONG lColor
= (LONG
)vColour
.GetPixel();
201 ::WinSetPresParam( m_hWnd
202 ,PP_HILITEFOREGROUNDCOLOR
206 vColour
= wxSystemSettingsNative::GetColour(wxSYS_COLOUR_HIGHLIGHT
);
207 lColor
= (LONG
)vColour
.GetPixel();
208 ::WinSetPresParam( m_hWnd
209 ,PP_HILITEBACKGROUNDCOLOR
223 } // end of wxListBox::Create
225 wxListBox::~wxListBox()
227 #if wxUSE_OWNER_DRAWN
228 size_t lUiCount
= m_aItems
.Count();
230 while (lUiCount
-- != 0)
232 delete m_aItems
[lUiCount
];
234 #endif // wxUSE_OWNER_DRAWN
235 } // end of wxListBox::~wxListBox
237 void wxListBox::SetupColours()
239 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
240 SetForegroundColour(GetParent()->GetForegroundColour());
241 } // end of wxListBox::SetupColours
243 // ----------------------------------------------------------------------------
244 // implementation of wxListBoxBase methods
245 // ----------------------------------------------------------------------------
247 void wxListBox::DoSetFirstItem(int N
)
249 wxCHECK_RET( IsValid(N
),
250 wxT("invalid index in wxListBox::SetFirstItem") );
252 ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX
, MPFROMLONG(N
), (MPARAM
)0);
253 } // end of wxListBox::DoSetFirstItem
255 void wxListBox::Delete(unsigned int n
)
257 wxCHECK_RET( IsValid(n
),
258 wxT("invalid index in wxListBox::Delete") );
260 #if wxUSE_OWNER_DRAWN
262 m_aItems
.RemoveAt(n
);
263 #else // !wxUSE_OWNER_DRAWN
264 if (HasClientObjectData())
266 delete GetClientObject(n
);
268 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
270 ::WinSendMsg(GetHwnd(), LM_DELETEITEM
, (MPARAM
)n
, (MPARAM
)0);
272 } // end of wxListBox::DoSetFirstItem
274 int wxListBox::DoAppend(const wxString
& rsItem
)
279 if (m_windowStyle
& wxLB_SORT
)
280 lIndexType
= LIT_SORTASCENDING
;
282 lIndexType
= LIT_END
;
284 lIndex
= (long)::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)lIndexType
, (MPARAM
)rsItem
.c_str());
287 #if wxUSE_OWNER_DRAWN
288 if (m_windowStyle
& wxLB_OWNERDRAW
)
290 wxOwnerDrawn
* pNewItem
= CreateItem(lIndex
); // dummy argument
294 pNewItem
->SetName(rsItem
);
295 m_aItems
.Insert(pNewItem
, lIndex
);
296 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, (MPARAM
)lIndex
, MPFROMP(pNewItem
));
297 pNewItem
->SetFont(GetFont());
301 } // end of wxListBox::DoAppend
303 void wxListBox::DoSetItems( const wxArrayString
& raChoices
,
304 void** ppClientData
)
306 BOOL bHideAndShow
= IsShown();
311 ::WinShowWindow(GetHwnd(), FALSE
);
313 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
314 m_nNumItems
= raChoices
.GetCount();
315 for (unsigned int i
= 0; i
< m_nNumItems
; i
++)
317 if (m_windowStyle
& wxLB_SORT
)
318 lIndexType
= LIT_SORTASCENDING
;
320 lIndexType
= LIT_END
;
321 ::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)lIndexType
, (MPARAM
)raChoices
[i
].c_str());
325 #if wxUSE_OWNER_DRAWN
326 wxASSERT_MSG(ppClientData
[i
] == NULL
,
327 wxT("Can't use client data with owner-drawn listboxes"));
328 #else // !wxUSE_OWNER_DRAWN
329 ::WinSendMsg(WinUtil_GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(lCount
), MPFROMP(ppClientData
[i
]));
330 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
334 #if wxUSE_OWNER_DRAWN
335 if ( m_windowStyle
& wxLB_OWNERDRAW
)
338 // First delete old items
340 WX_CLEAR_ARRAY(m_aItems
);
343 // Then create new ones
345 for (unsigned int ui
= 0; ui
< m_nNumItems
; ui
++)
347 wxOwnerDrawn
* pNewItem
= CreateItem(ui
);
349 pNewItem
->SetName(raChoices
[ui
]);
350 m_aItems
.Add(pNewItem
);
351 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(ui
), MPFROMP(pNewItem
));
354 #endif // wxUSE_OWNER_DRAWN
355 ::WinShowWindow(GetHwnd(), TRUE
);
356 } // end of wxListBox::DoSetItems
358 void wxListBox::Clear()
360 #if wxUSE_OWNER_DRAWN
361 unsigned int lUiCount
= m_aItems
.Count();
363 while (lUiCount
-- != 0)
365 delete m_aItems
[lUiCount
];
369 #else // !wxUSE_OWNER_DRAWN
370 if (HasClientObjectData())
372 for (unsigned int n
= 0; n
< m_lNumItems
; n
++)
374 delete GetClientObject(n
);
377 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
378 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
381 } // end of wxListBox::Clear
383 void wxListBox::DoSetSelection( int N
, bool bSelect
)
385 wxCHECK_RET( IsValid(N
),
386 wxT("invalid index in wxListBox::SetSelection") );
387 ::WinSendMsg( GetHwnd()
392 if(m_windowStyle
& wxLB_OWNERDRAW
)
394 } // end of wxListBox::SetSelection
396 bool wxListBox::IsSelected( int N
) const
398 wxCHECK_MSG( IsValid(N
), false,
399 wxT("invalid index in wxListBox::Selected") );
403 if (GetWindowStyleFlag() & wxLB_EXTENDED
)
406 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
408 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)(N
- 1), (MPARAM
)0));
412 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
414 return (lItem
== (LONG
)N
&& lItem
!= LIT_NONE
);
415 } // end of wxListBox::IsSelected
417 wxClientData
* wxListBox::DoGetItemClientObject(unsigned int n
) const
419 return (wxClientData
*)DoGetItemClientData(n
);
422 void* wxListBox::DoGetItemClientData(unsigned int n
) const
424 wxCHECK_MSG( IsValid(n
), NULL
,
425 wxT("invalid index in wxListBox::GetClientData") );
427 return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE
, MPFROMLONG(n
), (MPARAM
)0));
428 } // end of wxListBox::DoGetItemClientData
430 void wxListBox::DoSetItemClientObject(unsigned int n
, wxClientData
* pClientData
)
432 DoSetItemClientData(n
, pClientData
);
433 } // end of wxListBox::DoSetItemClientObject
435 void wxListBox::DoSetItemClientData(unsigned int n
, void* pClientData
)
437 wxCHECK_RET( IsValid(n
),
438 wxT("invalid index in wxListBox::SetClientData") );
440 #if wxUSE_OWNER_DRAWN
441 if ( m_windowStyle
& wxLB_OWNERDRAW
)
444 // Client data must be pointer to wxOwnerDrawn, otherwise we would crash
445 // in OnMeasure/OnDraw.
447 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
449 #endif // wxUSE_OWNER_DRAWN
451 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(n
), MPFROMP(pClientData
));
452 } // end of wxListBox::DoSetItemClientData
454 bool wxListBox::HasMultipleSelection() const
456 return (m_windowStyle
& wxLB_MULTIPLE
) || (m_windowStyle
& wxLB_EXTENDED
);
457 } // end of wxListBox::HasMultipleSelection
459 int wxListBox::GetSelections( wxArrayInt
& raSelections
) const
465 raSelections
.Empty();
466 if (HasMultipleSelection())
468 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
474 if (lItem
!= LIT_NONE
)
477 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
486 raSelections
.Alloc(nCount
);
487 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
494 raSelections
.Add((int)lItem
);
495 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
502 raSelections
.Add((int)lItem
);
507 else // single-selection listbox
509 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
515 raSelections
.Add((int)lItem
);
519 } // end of wxListBox::GetSelections
521 int wxListBox::GetSelection() const
523 wxCHECK_MSG( !HasMultipleSelection(),
525 wxT("GetSelection() can't be used with multiple-selection "
526 "listboxes, use GetSelections() instead.") );
528 return(LONGFROMMR(::WinSendMsg( GetHwnd()
534 } // end of wxListBox::GetSelection
536 wxString
wxListBox::GetString(unsigned int n
) const
542 wxCHECK_MSG( IsValid(n
), wxEmptyString
,
543 wxT("invalid index in wxListBox::GetClientData") );
545 lLen
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)n
, (MPARAM
)0));
546 zBuf
= new wxChar
[lLen
+ 1];
547 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT((SHORT
)n
, (SHORT
)lLen
), (MPARAM
)zBuf
);
552 } // end of wxListBox::GetString
554 void wxListBox::DoInsertItems(const wxArrayString
& asItems
, unsigned int nPos
)
556 wxCHECK_RET( IsValidInsert(nPos
),
557 wxT("invalid index in wxListBox::InsertItems") );
559 unsigned int nItems
= asItems
.GetCount();
561 for (unsigned int i
= 0; i
< nItems
; i
++)
563 int nIndex
= (int)::WinSendMsg( GetHwnd(),
565 MPFROMLONG((LONG
)(i
+ nPos
)),
566 (MPARAM
)asItems
[i
].c_str() );
568 wxOwnerDrawn
* pNewItem
= CreateItem(nIndex
);
570 pNewItem
->SetName(asItems
[i
]);
571 pNewItem
->SetFont(GetFont());
572 m_aItems
.Insert(pNewItem
, nIndex
);
573 ::WinSendMsg( GetHwnd()
575 ,(MPARAM
)((LONG
)nIndex
)
578 m_nNumItems
+= nItems
;
580 } // end of wxListBox::DoInsertItems
582 void wxListBox::SetString(unsigned int n
, const wxString
& rsString
)
584 wxCHECK_RET( IsValid(n
),
585 wxT("invalid index in wxListBox::SetString") );
588 // Remember the state of the item
590 bool bWasSelected
= IsSelected(n
);
591 void* pOldData
= NULL
;
592 wxClientData
* pOldObjData
= NULL
;
594 if (m_clientDataItemsType
== wxClientData_Void
)
595 pOldData
= GetClientData(n
);
596 else if (m_clientDataItemsType
== wxClientData_Object
)
597 pOldObjData
= GetClientObject(n
);
600 // Delete and recreate it
602 ::WinSendMsg( GetHwnd()
610 if (n
== (m_nNumItems
- 1))
613 ::WinSendMsg( GetHwnd()
616 ,(MPARAM
)rsString
.c_str()
620 // Restore the client data
623 SetClientData(n
, pOldData
);
624 else if (pOldObjData
)
625 SetClientObject(n
, pOldObjData
);
628 // We may have lost the selection
633 #if wxUSE_OWNER_DRAWN
634 if (m_windowStyle
& wxLB_OWNERDRAW
)
636 // Update item's text
638 m_aItems
[n
]->SetName(rsString
);
639 #endif //USE_OWNER_DRAWN
640 } // end of wxListBox::SetString
642 unsigned int wxListBox::GetCount() const
647 // ----------------------------------------------------------------------------
649 // ----------------------------------------------------------------------------
651 wxSize
wxListBox::DoGetBestSize() const
654 // Find the widest string
660 wxFont vFont
= (wxFont
)GetFont();
662 for (unsigned int i
= 0; i
< m_nNumItems
; i
++)
664 wxString
vStr(GetString(i
));
666 GetTextExtent( vStr
, &nLine
, NULL
);
667 if (nLine
> nListbox
)
672 // Give it some reasonable default value if there are no strings in the
679 // The listbox should be slightly larger than the widest string
681 wxGetCharSize( GetHWND()
688 int hListbox
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy
) * (wxMax(m_nNumItems
, 7));
690 return wxSize( nListbox
693 } // end of wxListBox::DoGetBestSize
695 // ----------------------------------------------------------------------------
697 // ----------------------------------------------------------------------------
699 bool wxListBox::OS2Command(
701 , WXWORD
WXUNUSED(wId
))
703 wxEventType eEvtType
;
705 if (uParam
== LN_SELECT
)
707 eEvtType
= wxEVT_COMMAND_LISTBOX_SELECTED
;
709 else if (uParam
== LN_ENTER
)
711 eEvtType
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
;
716 // Some event we're not interested in
720 wxCommandEvent
vEvent( eEvtType
724 vEvent
.SetEventObject(this);
726 wxArrayInt aSelections
;
728 int nCount
= GetSelections(aSelections
);
733 if (HasClientObjectData())
734 vEvent
.SetClientObject(GetClientObject(n
));
735 else if ( HasClientUntypedData() )
736 vEvent
.SetClientData(GetClientData(n
));
737 vEvent
.SetString(GetString(n
));
744 return GetEventHandler()->ProcessEvent(vEvent
);
745 } // end of wxListBox::OS2Command
747 // ----------------------------------------------------------------------------
748 // wxCheckListBox support
749 // ----------------------------------------------------------------------------
751 #if wxUSE_OWNER_DRAWN
757 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
759 long wxListBox::OS2OnMeasure(WXMEASUREITEMSTRUCT
* pItem
)
762 pItem
= (WXMEASUREITEMSTRUCT
*)new OWNERITEM
;
764 POWNERITEM pMeasureStruct
= (POWNERITEM
)pItem
;
768 // Only owner-drawn control should receive this message
770 wxCHECK( ((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
772 vDc
.SetFont(GetFont());
781 pMeasureStruct
->rclItem
.xRight
= (USHORT
)vWidth
;
782 pMeasureStruct
->rclItem
.xLeft
= 0;
783 pMeasureStruct
->rclItem
.yTop
= 0;
784 pMeasureStruct
->rclItem
.yBottom
= 0;
786 vHeight
= (wxCoord
)(vDc
.GetCharHeight() * 2.5);
787 pMeasureStruct
->rclItem
.yTop
= (USHORT
)vHeight
;
789 return long(MRFROM2SHORT((USHORT
)vHeight
, (USHORT
)vWidth
));
790 } // end of wxListBox::OS2OnMeasure
792 bool wxListBox::OS2OnDraw (
793 WXDRAWITEMSTRUCT
* pItem
796 POWNERITEM pDrawStruct
= (POWNERITEM
)pItem
;
797 LONG lItemID
= pDrawStruct
->idItem
;
802 // Only owner-drawn control should receive this message
804 wxCHECK(((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), false);
808 // The item may be -1 for an empty listbox
813 wxListBoxItem
* pData
= (wxListBoxItem
*)PVOIDFROMMR( ::WinSendMsg( GetHwnd()
815 ,MPFROMLONG(pDrawStruct
->idItem
)
820 wxCHECK(pData
, false );
823 wxPoint
pt1( pDrawStruct
->rclItem
.xLeft
, pDrawStruct
->rclItem
.yTop
);
824 wxPoint
pt2( pDrawStruct
->rclItem
.xRight
, pDrawStruct
->rclItem
.yBottom
);
825 wxRect
vRect( pt1
, pt2
);
827 vDc
.SetHPS(pDrawStruct
->hps
);
829 if (pDrawStruct
->fsAttribute
== pDrawStruct
->fsAttributeOld
)
832 // Entire Item needs to be redrawn (either it has reappeared from
833 // behind another window or is being displayed for the first time
835 eAction
= wxOwnerDrawn::wxODDrawAll
;
837 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
840 // If it is currently selected we let the system handle it
842 eStatus
|= wxOwnerDrawn::wxODSelected
;
844 if (pDrawStruct
->fsAttribute
& MIA_CHECKED
)
847 // If it is currently checked we draw our own
849 eStatus
|= wxOwnerDrawn::wxODChecked
;
850 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_CHECKED
;
852 if (pDrawStruct
->fsAttribute
& MIA_DISABLED
)
855 // If it is currently disabled we let the system handle it
857 eStatus
|= wxOwnerDrawn::wxODDisabled
;
860 // Don't really care about framed (indicationg focus) or NoDismiss
865 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
867 eAction
= wxOwnerDrawn::wxODDrawAll
;
868 eStatus
|= wxOwnerDrawn::wxODSelected
;
870 // Keep the system from trying to highlight with its bogus colors
872 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_HILITED
;
874 else if (!(pDrawStruct
->fsAttribute
& MIA_HILITED
))
876 eAction
= wxOwnerDrawn::wxODDrawAll
;
879 // Keep the system from trying to highlight with its bogus colors
881 pDrawStruct
->fsAttribute
= pDrawStruct
->fsAttributeOld
&= ~MIA_HILITED
;
886 // For now we don't care about anything else
887 // just ignore the entire message!
892 return pData
->OnDrawItem( vDc
894 ,(wxOwnerDrawn::wxODAction
)eAction
895 ,(wxOwnerDrawn::wxODStatus
)eStatus
897 } // end of wxListBox::OS2OnDraw
899 #endif // ndef for wxUSE_OWNER_DRAWN
901 #endif // wxUSE_LISTBOX