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/private.h"
38 #include "wx/ownerdrw.h"
41 IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControlWithItems)
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::DoDeleteOneItem(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 #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
265 ::WinSendMsg(GetHwnd(), LM_DELETEITEM, (MPARAM)n, (MPARAM)0);
267 } // end of wxListBox::DoSetFirstItem
269 int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items,
272 wxClientDataType type)
276 bool incrementPos = false;
279 lIndexType = LIT_SORTASCENDING;
280 else if (pos == GetCount())
281 lIndexType = LIT_END;
284 lIndexType = (LONG)pos;
290 unsigned int count = items.GetCount();
291 for (unsigned int i = 0; i < count; i++)
293 n = (int)::WinSendMsg(GetHwnd(), LM_INSERTITEM, (MPARAM)lIndexType, (MPARAM)items[i].wx_str());
296 wxLogLastError(_T("WinSendMsg(LM_INSERTITEM)"));
302 #if wxUSE_OWNER_DRAWN
303 if (HasFlag(wxLB_OWNERDRAW))
305 wxOwnerDrawn* pNewItem = CreateItem(n); // dummy argument
306 wxScreenDC vDc; // FIXME: is it really needed here?
308 pNewItem->SetName(items[i]);
309 m_aItems.Insert(pNewItem, n);
310 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE, (MPARAM)n, MPFROMP(pNewItem));
311 pNewItem->SetFont(GetFont());
314 AssignNewItemClientData(n, clientData, i, type);
321 } // end of wxListBox::DoInsertAppendItemsWithData
323 void wxListBox::DoClear()
325 #if wxUSE_OWNER_DRAWN
326 unsigned int lUiCount = m_aItems.Count();
328 while (lUiCount-- != 0)
330 delete m_aItems[lUiCount];
334 #endif // wxUSE_OWNER_DRAWN
335 ::WinSendMsg(GetHwnd(), LM_DELETEALL, (MPARAM)0, (MPARAM)0);
338 } // end of wxListBox::Clear
340 void wxListBox::DoSetSelection( int N, bool bSelect)
342 wxCHECK_RET( IsValid(N),
343 wxT("invalid index in wxListBox::SetSelection") );
344 ::WinSendMsg( GetHwnd()
349 if(m_windowStyle & wxLB_OWNERDRAW)
351 } // end of wxListBox::SetSelection
353 bool wxListBox::IsSelected( int N ) const
355 wxCHECK_MSG( IsValid(N), false,
356 wxT("invalid index in wxListBox::Selected") );
360 if (GetWindowStyleFlag() & wxLB_EXTENDED)
363 lItem = LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION, (MPARAM)LIT_FIRST, (MPARAM)0));
365 lItem = LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION, (MPARAM)(N - 1), (MPARAM)0));
369 lItem = LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION, (MPARAM)LIT_FIRST, (MPARAM)0));
371 return (lItem == (LONG)N && lItem != LIT_NONE);
372 } // end of wxListBox::IsSelected
374 void* wxListBox::DoGetItemClientData(unsigned int n) const
376 wxCHECK_MSG( IsValid(n), NULL,
377 wxT("invalid index in wxListBox::GetClientData") );
379 return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE, MPFROMLONG(n), (MPARAM)0));
380 } // end of wxListBox::DoGetItemClientData
382 void wxListBox::DoSetItemClientData(unsigned int n, void* pClientData)
384 wxCHECK_RET( IsValid(n),
385 wxT("invalid index in wxListBox::SetClientData") );
387 #if wxUSE_OWNER_DRAWN
388 if ( m_windowStyle & wxLB_OWNERDRAW )
391 // Client data must be pointer to wxOwnerDrawn, otherwise we would crash
392 // in OnMeasure/OnDraw.
394 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
396 #endif // wxUSE_OWNER_DRAWN
398 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE, MPFROMLONG(n), MPFROMP(pClientData));
399 } // end of wxListBox::DoSetItemClientData
401 bool wxListBox::HasMultipleSelection() const
403 return (m_windowStyle & wxLB_MULTIPLE) || (m_windowStyle & wxLB_EXTENDED);
404 } // end of wxListBox::HasMultipleSelection
406 int wxListBox::GetSelections( wxArrayInt& raSelections ) const
412 raSelections.Empty();
413 if (HasMultipleSelection())
415 lItem = LONGFROMMR(::WinSendMsg( GetHwnd()
421 if (lItem != LIT_NONE)
424 while ((lItem = LONGFROMMR(::WinSendMsg( GetHwnd()
433 raSelections.Alloc(nCount);
434 lItem = LONGFROMMR(::WinSendMsg( GetHwnd()
441 raSelections.Add((int)lItem);
442 while ((lItem = LONGFROMMR(::WinSendMsg( GetHwnd()
449 raSelections.Add((int)lItem);
454 else // single-selection listbox
456 lItem = LONGFROMMR(::WinSendMsg( GetHwnd()
462 raSelections.Add((int)lItem);
466 } // end of wxListBox::GetSelections
468 int wxListBox::GetSelection() const
470 wxCHECK_MSG( !HasMultipleSelection(),
472 wxT("GetSelection() can't be used with multiple-selection "
473 "listboxes, use GetSelections() instead.") );
475 return(LONGFROMMR(::WinSendMsg( GetHwnd()
481 } // end of wxListBox::GetSelection
483 wxString wxListBox::GetString(unsigned int n) const
489 wxCHECK_MSG( IsValid(n), wxEmptyString,
490 wxT("invalid index in wxListBox::GetClientData") );
492 lLen = LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH, (MPARAM)n, (MPARAM)0));
493 zBuf = new wxChar[lLen + 1];
494 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT, MPFROM2SHORT((SHORT)n, (SHORT)lLen), (MPARAM)zBuf);
499 } // end of wxListBox::GetString
501 void wxListBox::SetString(unsigned int n, const wxString& rsString)
503 wxCHECK_RET( IsValid(n),
504 wxT("invalid index in wxListBox::SetString") );
507 // Remember the state of the item
509 bool bWasSelected = IsSelected(n);
510 void* pOldData = NULL;
511 wxClientData* pOldObjData = NULL;
513 if (m_clientDataItemsType == wxClientData_Void)
514 pOldData = GetClientData(n);
515 else if (m_clientDataItemsType == wxClientData_Object)
516 pOldObjData = GetClientObject(n);
519 // Delete and recreate it
521 ::WinSendMsg( GetHwnd()
529 if (n == (m_nNumItems - 1))
532 ::WinSendMsg( GetHwnd()
535 ,(MPARAM)rsString.wx_str()
539 // Restore the client data
542 SetClientData(n, pOldData);
543 else if (pOldObjData)
544 SetClientObject(n, pOldObjData);
547 // We may have lost the selection
552 #if wxUSE_OWNER_DRAWN
553 if (m_windowStyle & wxLB_OWNERDRAW)
555 // Update item's text
557 m_aItems[n]->SetName(rsString);
558 #endif //USE_OWNER_DRAWN
559 } // end of wxListBox::SetString
561 unsigned int wxListBox::GetCount() const
566 // ----------------------------------------------------------------------------
568 // ----------------------------------------------------------------------------
570 wxSize wxListBox::DoGetBestSize() const
573 // Find the widest string
579 wxFont vFont = (wxFont)GetFont();
581 for (unsigned int i = 0; i < m_nNumItems; i++)
583 wxString vStr(GetString(i));
585 GetTextExtent( vStr, &nLine, NULL );
586 if (nLine > nListbox)
591 // Give it some reasonable default value if there are no strings in the
598 // The listbox should be slightly larger than the widest string
600 wxGetCharSize( GetHWND()
607 int hListbox = EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy) * (wxMax(m_nNumItems, 7));
609 return wxSize( nListbox
612 } // end of wxListBox::DoGetBestSize
614 // ----------------------------------------------------------------------------
616 // ----------------------------------------------------------------------------
618 bool wxListBox::OS2Command(
620 , WXWORD WXUNUSED(wId))
622 wxEventType eEvtType;
624 if (uParam == LN_SELECT)
626 eEvtType = wxEVT_COMMAND_LISTBOX_SELECTED;
628 else if (uParam == LN_ENTER)
630 eEvtType = wxEVT_COMMAND_LISTBOX_DOUBLECLICKED;
635 // Some event we're not interested in
639 wxCommandEvent vEvent( eEvtType
643 vEvent.SetEventObject(this);
645 wxArrayInt aSelections;
647 int nCount = GetSelections(aSelections);
652 if (HasClientObjectData())
653 vEvent.SetClientObject(GetClientObject(n));
654 else if ( HasClientUntypedData() )
655 vEvent.SetClientData(GetClientData(n));
656 vEvent.SetString(GetString(n));
663 return GetEventHandler()->ProcessEvent(vEvent);
664 } // end of wxListBox::OS2Command
666 // ----------------------------------------------------------------------------
667 // wxCheckListBox support
668 // ----------------------------------------------------------------------------
670 #if wxUSE_OWNER_DRAWN
676 #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
678 long wxListBox::OS2OnMeasure(WXMEASUREITEMSTRUCT* pItem)
681 pItem = (WXMEASUREITEMSTRUCT*)new OWNERITEM;
683 POWNERITEM pMeasureStruct = (POWNERITEM)pItem;
687 // Only owner-drawn control should receive this message
689 wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), FALSE );
691 vDc.SetFont(GetFont());
700 pMeasureStruct->rclItem.xRight = (USHORT)vWidth;
701 pMeasureStruct->rclItem.xLeft = 0;
702 pMeasureStruct->rclItem.yTop = 0;
703 pMeasureStruct->rclItem.yBottom = 0;
705 vHeight = (wxCoord)(vDc.GetCharHeight() * 2.5);
706 pMeasureStruct->rclItem.yTop = (USHORT)vHeight;
708 return long(MRFROM2SHORT((USHORT)vHeight, (USHORT)vWidth));
709 } // end of wxListBox::OS2OnMeasure
711 bool wxListBox::OS2OnDraw (
712 WXDRAWITEMSTRUCT* pItem
715 POWNERITEM pDrawStruct = (POWNERITEM)pItem;
716 LONG lItemID = pDrawStruct->idItem;
721 // Only owner-drawn control should receive this message
723 wxCHECK(((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), false);
727 // The item may be -1 for an empty listbox
732 wxListBoxItem* pData = (wxListBoxItem*)PVOIDFROMMR( ::WinSendMsg( GetHwnd()
734 ,MPFROMLONG(pDrawStruct->idItem)
739 wxCHECK(pData, false );
742 wxPoint pt1( pDrawStruct->rclItem.xLeft, pDrawStruct->rclItem.yTop );
743 wxPoint pt2( pDrawStruct->rclItem.xRight, pDrawStruct->rclItem.yBottom );
744 wxRect vRect( pt1, pt2 );
746 vDc.SetHPS(pDrawStruct->hps);
748 if (pDrawStruct->fsAttribute == pDrawStruct->fsAttributeOld)
751 // Entire Item needs to be redrawn (either it has reappeared from
752 // behind another window or is being displayed for the first time
754 eAction = wxOwnerDrawn::wxODDrawAll;
756 if (pDrawStruct->fsAttribute & MIA_HILITED)
759 // If it is currently selected we let the system handle it
761 eStatus |= wxOwnerDrawn::wxODSelected;
763 if (pDrawStruct->fsAttribute & MIA_CHECKED)
766 // If it is currently checked we draw our own
768 eStatus |= wxOwnerDrawn::wxODChecked;
769 pDrawStruct->fsAttributeOld = pDrawStruct->fsAttribute &= ~MIA_CHECKED;
771 if (pDrawStruct->fsAttribute & MIA_DISABLED)
774 // If it is currently disabled we let the system handle it
776 eStatus |= wxOwnerDrawn::wxODDisabled;
779 // Don't really care about framed (indicationg focus) or NoDismiss
784 if (pDrawStruct->fsAttribute & MIA_HILITED)
786 eAction = wxOwnerDrawn::wxODDrawAll;
787 eStatus |= wxOwnerDrawn::wxODSelected;
789 // Keep the system from trying to highlight with its bogus colors
791 pDrawStruct->fsAttributeOld = pDrawStruct->fsAttribute &= ~MIA_HILITED;
793 else if (!(pDrawStruct->fsAttribute & MIA_HILITED))
795 eAction = wxOwnerDrawn::wxODDrawAll;
798 // Keep the system from trying to highlight with its bogus colors
800 pDrawStruct->fsAttribute = pDrawStruct->fsAttributeOld &= ~MIA_HILITED;
805 // For now we don't care about anything else
806 // just ignore the entire message!
811 return pData->OnDrawItem( vDc
813 ,(wxOwnerDrawn::wxODAction)eAction
814 ,(wxOwnerDrawn::wxODStatus)eStatus
816 } // end of wxListBox::OS2OnDraw
818 #endif // ndef for wxUSE_OWNER_DRAWN
820 #endif // wxUSE_LISTBOX