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/listbox.h"
20 #include "wx/dynarray.h"
21 #include "wx/settings.h"
25 #include "wx/dcscreen.h"
27 #include "wx/scrolwin.h"
29 #include "wx/window.h"
32 #include "wx/os2/dcclient.h"
33 #include "wx/os2/private.h"
39 #include "wx/ownerdrw.h"
42 IMPLEMENT_DYNAMIC_CLASS(wxListBox
, wxControlWithItems
)
44 // ============================================================================
45 // list box item declaration and implementation
46 // ============================================================================
50 class wxListBoxItem
: public wxOwnerDrawn
53 wxListBoxItem(const wxString
& rsStr
= wxEmptyString
);
56 wxListBoxItem::wxListBoxItem(
64 // No bitmaps/checkmarks
67 } // end of wxListBoxItem::wxListBoxItem
69 wxOwnerDrawn
* wxListBox::CreateItem( size_t WXUNUSED(n
) )
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(
92 , const wxArrayString
& asChoices
94 , const wxValidator
& rValidator
95 , const wxString
& rsName
98 wxCArrayString
chs(asChoices
);
100 return Create(pParent
, vId
, rPos
, rSize
, chs
.GetCount(), chs
.GetStrings(),
101 lStyle
, rValidator
, rsName
);
104 bool wxListBox::Create( wxWindow
* pParent
,
109 const wxString asChoices
[],
111 const wxValidator
& rValidator
,
112 const wxString
& rsName
)
120 SetValidator(rValidator
);
124 pParent
->AddChild(this);
126 wxSystemSettings vSettings
;
128 SetBackgroundColour(vSettings
.GetColour(wxSYS_COLOUR_WINDOW
));
129 SetForegroundColour(pParent
->GetForegroundColour());
131 m_windowId
= (vId
== -1) ? (int)NewControlId() : vId
;
135 int nWidth
= rSize
.x
;
136 int nHeight
= rSize
.y
;
138 m_windowStyle
= lStyle
;
142 if (m_windowStyle
& wxCLIP_SIBLINGS
)
143 lStyle
|= WS_CLIPSIBLINGS
;
144 if (m_windowStyle
& wxLB_MULTIPLE
)
145 lStyle
|= LS_MULTIPLESEL
;
146 else if (m_windowStyle
& wxLB_EXTENDED
)
147 lStyle
|= LS_EXTENDEDSEL
;
148 if (m_windowStyle
& wxLB_HSCROLL
)
149 lStyle
|= LS_HORZSCROLL
;
150 if (m_windowStyle
& wxLB_OWNERDRAW
)
151 lStyle
|= LS_OWNERDRAW
;
154 // Without this style, you get unexpected heights, so e.g. constraint layout
155 // doesn't work properly
157 lStyle
|= LS_NOADJUSTPOS
;
159 m_hWnd
= (WXHWND
)::WinCreateWindow( GetWinHwnd(pParent
) // Parent
160 ,WC_LISTBOX
// Default Listbox class
161 ,"LISTBOX" // Control's name
162 ,lStyle
// Initial Style
163 ,0, 0, 0, 0 // Position and size
164 ,GetWinHwnd(pParent
) // Owner
166 ,(HMENU
)m_windowId
// Id
167 ,NULL
// Control Data
168 ,NULL
// Presentation Parameters
176 // Subclass again for purposes of dialog editing mode
182 for (lUi
= 0; lUi
< (LONG
)n
; lUi
++)
184 Append(asChoices
[lUi
]);
186 wxFont
* pTextFont
= new wxFont( 10
194 // Set OS/2 system colours for Listbox items and highlighting
198 vColour
= wxSystemSettingsNative::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
);
200 LONG lColor
= (LONG
)vColour
.GetPixel();
202 ::WinSetPresParam( m_hWnd
203 ,PP_HILITEFOREGROUNDCOLOR
207 vColour
= wxSystemSettingsNative::GetColour(wxSYS_COLOUR_HIGHLIGHT
);
208 lColor
= (LONG
)vColour
.GetPixel();
209 ::WinSetPresParam( m_hWnd
210 ,PP_HILITEBACKGROUNDCOLOR
224 } // end of wxListBox::Create
226 wxListBox::~wxListBox()
228 #if wxUSE_OWNER_DRAWN
229 size_t lUiCount
= m_aItems
.Count();
231 while (lUiCount
-- != 0)
233 delete m_aItems
[lUiCount
];
235 #endif // wxUSE_OWNER_DRAWN
236 } // end of wxListBox::~wxListBox
238 void wxListBox::SetupColours()
240 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
241 SetForegroundColour(GetParent()->GetForegroundColour());
242 } // end of wxListBox::SetupColours
244 // ----------------------------------------------------------------------------
245 // implementation of wxListBoxBase methods
246 // ----------------------------------------------------------------------------
248 void wxListBox::DoSetFirstItem(int N
)
250 wxCHECK_RET( IsValid(N
),
251 wxT("invalid index in wxListBox::SetFirstItem") );
253 ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX
, MPFROMLONG(N
), (MPARAM
)0);
254 } // end of wxListBox::DoSetFirstItem
256 void wxListBox::DoDeleteOneItem(unsigned int n
)
258 wxCHECK_RET( IsValid(n
),
259 wxT("invalid index in wxListBox::Delete") );
261 #if wxUSE_OWNER_DRAWN
263 m_aItems
.RemoveAt(n
);
264 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
266 ::WinSendMsg(GetHwnd(), LM_DELETEITEM
, (MPARAM
)n
, (MPARAM
)0);
268 } // end of wxListBox::DoSetFirstItem
270 int wxListBox::DoInsertItems(const wxArrayStringsAdapter
& items
,
273 wxClientDataType type
)
277 bool incrementPos
= false;
280 lIndexType
= LIT_SORTASCENDING
;
281 else if (pos
== GetCount())
282 lIndexType
= LIT_END
;
285 lIndexType
= (LONG
)pos
;
291 unsigned int count
= items
.GetCount();
292 for (unsigned int i
= 0; i
< count
; i
++)
294 n
= (int)::WinSendMsg(GetHwnd(), LM_INSERTITEM
, (MPARAM
)lIndexType
, (MPARAM
)items
[i
].wx_str());
297 wxLogLastError(_T("WinSendMsg(LM_INSERTITEM)"));
303 #if wxUSE_OWNER_DRAWN
304 if (HasFlag(wxLB_OWNERDRAW
))
306 wxOwnerDrawn
* pNewItem
= CreateItem(n
); // dummy argument
307 wxScreenDC vDc
; // FIXME: is it really needed here?
309 pNewItem
->SetName(items
[i
]);
310 m_aItems
.Insert(pNewItem
, n
);
311 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, (MPARAM
)n
, MPFROMP(pNewItem
));
312 pNewItem
->SetFont(GetFont());
315 AssignNewItemClientData(n
, clientData
, i
, type
);
322 } // end of wxListBox::DoInsertAppendItemsWithData
324 void wxListBox::DoClear()
326 #if wxUSE_OWNER_DRAWN
327 unsigned int lUiCount
= m_aItems
.Count();
329 while (lUiCount
-- != 0)
331 delete m_aItems
[lUiCount
];
335 #endif // wxUSE_OWNER_DRAWN
336 ::WinSendMsg(GetHwnd(), LM_DELETEALL
, (MPARAM
)0, (MPARAM
)0);
339 } // end of wxListBox::Clear
341 void wxListBox::DoSetSelection( int N
, bool bSelect
)
343 wxCHECK_RET( IsValid(N
),
344 wxT("invalid index in wxListBox::SetSelection") );
345 ::WinSendMsg( GetHwnd()
350 if(m_windowStyle
& wxLB_OWNERDRAW
)
352 } // end of wxListBox::SetSelection
354 bool wxListBox::IsSelected( int N
) const
356 wxCHECK_MSG( IsValid(N
), false,
357 wxT("invalid index in wxListBox::Selected") );
361 if (GetWindowStyleFlag() & wxLB_EXTENDED
)
364 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
366 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)(N
- 1), (MPARAM
)0));
370 lItem
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION
, (MPARAM
)LIT_FIRST
, (MPARAM
)0));
372 return (lItem
== (LONG
)N
&& lItem
!= LIT_NONE
);
373 } // end of wxListBox::IsSelected
375 void* wxListBox::DoGetItemClientData(unsigned int n
) const
377 wxCHECK_MSG( IsValid(n
), NULL
,
378 wxT("invalid index in wxListBox::GetClientData") );
380 return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE
, MPFROMLONG(n
), (MPARAM
)0));
381 } // end of wxListBox::DoGetItemClientData
383 void wxListBox::DoSetItemClientData(unsigned int n
, void* pClientData
)
385 wxCHECK_RET( IsValid(n
),
386 wxT("invalid index in wxListBox::SetClientData") );
388 #if wxUSE_OWNER_DRAWN
389 if ( m_windowStyle
& wxLB_OWNERDRAW
)
392 // Client data must be pointer to wxOwnerDrawn, otherwise we would crash
393 // in OnMeasure/OnDraw.
395 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
397 #endif // wxUSE_OWNER_DRAWN
399 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE
, MPFROMLONG(n
), MPFROMP(pClientData
));
400 } // end of wxListBox::DoSetItemClientData
402 bool wxListBox::HasMultipleSelection() const
404 return (m_windowStyle
& wxLB_MULTIPLE
) || (m_windowStyle
& wxLB_EXTENDED
);
405 } // end of wxListBox::HasMultipleSelection
407 int wxListBox::GetSelections( wxArrayInt
& raSelections
) const
413 raSelections
.Empty();
414 if (HasMultipleSelection())
416 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
422 if (lItem
!= LIT_NONE
)
425 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
434 raSelections
.Alloc(nCount
);
435 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
442 raSelections
.Add((int)lItem
);
443 while ((lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
450 raSelections
.Add((int)lItem
);
455 else // single-selection listbox
457 lItem
= LONGFROMMR(::WinSendMsg( GetHwnd()
463 raSelections
.Add((int)lItem
);
467 } // end of wxListBox::GetSelections
469 int wxListBox::GetSelection() const
471 wxCHECK_MSG( !HasMultipleSelection(),
473 wxT("GetSelection() can't be used with multiple-selection "
474 "listboxes, use GetSelections() instead.") );
476 return(LONGFROMMR(::WinSendMsg( GetHwnd()
482 } // end of wxListBox::GetSelection
484 wxString
wxListBox::GetString(unsigned int n
) const
490 wxCHECK_MSG( IsValid(n
), wxEmptyString
,
491 wxT("invalid index in wxListBox::GetClientData") );
493 lLen
= LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH
, (MPARAM
)n
, (MPARAM
)0));
494 zBuf
= new wxChar
[lLen
+ 1];
495 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT
, MPFROM2SHORT((SHORT
)n
, (SHORT
)lLen
), (MPARAM
)zBuf
);
500 } // end of wxListBox::GetString
502 void wxListBox::SetString(unsigned int n
, const wxString
& rsString
)
504 wxCHECK_RET( IsValid(n
),
505 wxT("invalid index in wxListBox::SetString") );
508 // Remember the state of the item
510 bool bWasSelected
= IsSelected(n
);
511 void* pOldData
= NULL
;
512 wxClientData
* pOldObjData
= NULL
;
514 if ( HasClientUntypedData() )
515 pOldData
= GetClientData(n
);
516 else if ( HasClientObjectData() )
517 pOldObjData
= GetClientObject(n
);
520 // Delete and recreate it
522 ::WinSendMsg( GetHwnd()
530 if (n
== (m_nNumItems
- 1))
533 ::WinSendMsg( GetHwnd()
536 ,(MPARAM
)rsString
.wx_str()
540 // Restore the client data
543 SetClientData(n
, pOldData
);
544 else if (pOldObjData
)
545 SetClientObject(n
, pOldObjData
);
548 // We may have lost the selection
553 #if wxUSE_OWNER_DRAWN
554 if (m_windowStyle
& wxLB_OWNERDRAW
)
556 // Update item's text
558 m_aItems
[n
]->SetName(rsString
);
559 #endif //USE_OWNER_DRAWN
560 } // end of wxListBox::SetString
562 unsigned int wxListBox::GetCount() const
567 // ----------------------------------------------------------------------------
569 // ----------------------------------------------------------------------------
571 wxSize
wxListBox::DoGetBestSize() const
574 // Find the widest string
580 wxFont vFont
= (wxFont
)GetFont();
582 for (unsigned int i
= 0; i
< m_nNumItems
; i
++)
584 wxString
vStr(GetString(i
));
586 GetTextExtent( vStr
, &nLine
, NULL
);
587 if (nLine
> nListbox
)
592 // Give it some reasonable default value if there are no strings in the
599 // The listbox should be slightly larger than the widest string
601 wxGetCharSize( GetHWND()
608 int hListbox
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy
) * (wxMax(m_nNumItems
, 7));
610 return wxSize( nListbox
613 } // end of wxListBox::DoGetBestSize
615 // ----------------------------------------------------------------------------
617 // ----------------------------------------------------------------------------
619 bool wxListBox::OS2Command(
621 , WXWORD
WXUNUSED(wId
))
623 wxEventType eEvtType
;
625 if (uParam
== LN_SELECT
)
627 eEvtType
= wxEVT_COMMAND_LISTBOX_SELECTED
;
629 else if (uParam
== LN_ENTER
)
631 eEvtType
= wxEVT_COMMAND_LISTBOX_DOUBLECLICKED
;
636 // Some event we're not interested in
640 wxCommandEvent
vEvent( eEvtType
644 vEvent
.SetEventObject(this);
646 wxArrayInt aSelections
;
648 int nCount
= GetSelections(aSelections
);
653 if (HasClientObjectData())
654 vEvent
.SetClientObject(GetClientObject(n
));
655 else if ( HasClientUntypedData() )
656 vEvent
.SetClientData(GetClientData(n
));
657 vEvent
.SetString(GetString(n
));
664 return HandleWindowEvent(vEvent
);
665 } // end of wxListBox::OS2Command
667 // ----------------------------------------------------------------------------
668 // wxCheckListBox support
669 // ----------------------------------------------------------------------------
671 #if wxUSE_OWNER_DRAWN
677 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
679 long wxListBox::OS2OnMeasure(WXMEASUREITEMSTRUCT
* pItem
)
682 pItem
= (WXMEASUREITEMSTRUCT
*)new OWNERITEM
;
684 POWNERITEM pMeasureStruct
= (POWNERITEM
)pItem
;
688 // Only owner-drawn control should receive this message
690 wxCHECK( ((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), FALSE
);
692 vDc
.SetFont(GetFont());
701 pMeasureStruct
->rclItem
.xRight
= (USHORT
)vWidth
;
702 pMeasureStruct
->rclItem
.xLeft
= 0;
703 pMeasureStruct
->rclItem
.yTop
= 0;
704 pMeasureStruct
->rclItem
.yBottom
= 0;
706 vHeight
= (wxCoord
)(vDc
.GetCharHeight() * 2.5);
707 pMeasureStruct
->rclItem
.yTop
= (USHORT
)vHeight
;
709 return long(MRFROM2SHORT((USHORT
)vHeight
, (USHORT
)vWidth
));
710 } // end of wxListBox::OS2OnMeasure
712 bool wxListBox::OS2OnDraw (
713 WXDRAWITEMSTRUCT
* pItem
716 POWNERITEM pDrawStruct
= (POWNERITEM
)pItem
;
717 LONG lItemID
= pDrawStruct
->idItem
;
722 // Only owner-drawn control should receive this message
724 wxCHECK(((m_windowStyle
& wxLB_OWNERDRAW
) == wxLB_OWNERDRAW
), false);
728 // The item may be -1 for an empty listbox
733 wxListBoxItem
* pData
= (wxListBoxItem
*)PVOIDFROMMR( ::WinSendMsg( GetHwnd()
735 ,MPFROMLONG(pDrawStruct
->idItem
)
740 wxCHECK(pData
, false );
742 wxClientDC
vDc(this);
743 wxPMDCImpl
*impl
= (wxPMDCImpl
*) vDc
.GetImpl();
744 wxPoint
pt1( pDrawStruct
->rclItem
.xLeft
, pDrawStruct
->rclItem
.yTop
);
745 wxPoint
pt2( pDrawStruct
->rclItem
.xRight
, pDrawStruct
->rclItem
.yBottom
);
746 wxRect
vRect( pt1
, pt2
);
748 impl
->SetHPS(pDrawStruct
->hps
);
750 if (pDrawStruct
->fsAttribute
== pDrawStruct
->fsAttributeOld
)
753 // Entire Item needs to be redrawn (either it has reappeared from
754 // behind another window or is being displayed for the first time
756 eAction
= wxOwnerDrawn::wxODDrawAll
;
758 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
761 // If it is currently selected we let the system handle it
763 eStatus
|= wxOwnerDrawn::wxODSelected
;
765 if (pDrawStruct
->fsAttribute
& MIA_CHECKED
)
768 // If it is currently checked we draw our own
770 eStatus
|= wxOwnerDrawn::wxODChecked
;
771 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_CHECKED
;
773 if (pDrawStruct
->fsAttribute
& MIA_DISABLED
)
776 // If it is currently disabled we let the system handle it
778 eStatus
|= wxOwnerDrawn::wxODDisabled
;
781 // Don't really care about framed (indicationg focus) or NoDismiss
786 if (pDrawStruct
->fsAttribute
& MIA_HILITED
)
788 eAction
= wxOwnerDrawn::wxODDrawAll
;
789 eStatus
|= wxOwnerDrawn::wxODSelected
;
791 // Keep the system from trying to highlight with its bogus colors
793 pDrawStruct
->fsAttributeOld
= pDrawStruct
->fsAttribute
&= ~MIA_HILITED
;
795 else if (!(pDrawStruct
->fsAttribute
& MIA_HILITED
))
797 eAction
= wxOwnerDrawn::wxODDrawAll
;
800 // Keep the system from trying to highlight with its bogus colors
802 pDrawStruct
->fsAttribute
= pDrawStruct
->fsAttributeOld
&= ~MIA_HILITED
;
807 // For now we don't care about anything else
808 // just ignore the entire message!
813 return pData
->OnDrawItem( vDc
815 ,(wxOwnerDrawn::wxODAction
)eAction
816 ,(wxOwnerDrawn::wxODStatus
)eStatus
818 } // end of wxListBox::OS2OnDraw
820 #endif // ndef for wxUSE_OWNER_DRAWN
822 #endif // wxUSE_LISTBOX