]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/os2/listbox.cpp
fix for wxComboBox::GetSelection from inside event handler
[wxWidgets.git] / src / os2 / listbox.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: listbox.cpp
3// Purpose: wxListBox
4// Author: David Webster
5// Modified by:
6// Created: 10/09/99
7// RCS-ID: $Id$
8// Copyright: (c) David Webster
9// Licence: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#include "wx/window.h"
16#include "wx/os2/private.h"
17
18#ifndef WX_PRECOMP
19#include "wx/listbox.h"
20#include "wx/settings.h"
21#include "wx/brush.h"
22#include "wx/font.h"
23#include "wx/dc.h"
24#include "wx/utils.h"
25#endif
26
27#define INCL_M
28#include <os2.h>
29
30#include "wx/dynarray.h"
31#include "wx/log.h"
32
33#if wxUSE_LISTBOX
34
35#if wxUSE_OWNER_DRAWN
36 #include "wx/ownerdrw.h"
37#endif
38
39 IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
40
41// ============================================================================
42// list box item declaration and implementation
43// ============================================================================
44
45#if wxUSE_OWNER_DRAWN
46
47class wxListBoxItem : public wxOwnerDrawn
48{
49public:
50 wxListBoxItem(const wxString& rsStr = "");
51};
52
53wxListBoxItem::wxListBoxItem(
54 const wxString& rsStr
55)
56: wxOwnerDrawn( rsStr
57 ,FALSE
58 )
59{
60 //
61 // No bitmaps/checkmarks
62 //
63 SetMarginWidth(0);
64} // end of wxListBoxItem::wxListBoxItem
65
66wxOwnerDrawn* wxListBox::CreateItem(
67 size_t n
68)
69{
70 return new wxListBoxItem();
71} // end of wxListBox::CreateItem
72
73#endif //USE_OWNER_DRAWN
74
75// ============================================================================
76// list box control implementation
77// ============================================================================
78
79// Listbox item
80wxListBox::wxListBox()
81{
82 m_nNumItems = 0;
83 m_nSelected = 0;
84} // end of wxListBox::wxListBox
85
86bool wxListBox::Create(
87 wxWindow* pParent
88, wxWindowID vId
89, const wxPoint& rPos
90, const wxSize& rSize
91, int n
92, const wxString asChoices[]
93, long lStyle
94#if wxUSE_VALIDATORS
95, const wxValidator& rValidator
96#endif
97, const wxString& rsName
98)
99{
100 m_nNumItems = 0;
101 m_hWnd = 0;
102 m_nSelected = 0;
103
104 SetName(rsName);
105#if wxUSE_VALIDATORS
106 SetValidator(rValidator);
107#endif
108
109 if (pParent)
110 pParent->AddChild(this);
111
112 wxSystemSettings vSettings;
113
114 SetBackgroundColour(vSettings.GetSystemColour(wxSYS_COLOUR_WINDOW));
115 SetForegroundColour(pParent->GetForegroundColour());
116
117 m_windowId = (vId == -1) ? (int)NewControlId() : vId;
118
119 int nX = rPos.x;
120 int nY = rPos.y;
121 int nWidth = rSize.x;
122 int nHeight = rSize.y;
123
124 m_windowStyle = lStyle;
125
126 lStyle = WS_VISIBLE;
127
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;
138
139 //
140 // Without this style, you get unexpected heights, so e.g. constraint layout
141 // doesn't work properly
142 //
143 lStyle |= LS_NOADJUSTPOS;
144
145 m_hWnd = (WXHWND)::WinCreateWindow( GetWinHwnd(pParent) // Parent
146 ,WC_LISTBOX // Default Listbox class
147 ,"LISTBOX" // Control's name
148 ,lStyle // Initial Style
149 ,0, 0, 0, 0 // Position and size
150 ,GetWinHwnd(pParent) // Owner
151 ,HWND_TOP // Z-Order
152 ,(HMENU)m_windowId // Id
153 ,NULL // Control Data
154 ,NULL // Presentation Parameters
155 );
156 if (m_hWnd == 0)
157 {
158 return FALSE;
159 }
160
161 //
162 // Subclass again for purposes of dialog editing mode
163 //
164 SubclassWin(m_hWnd);
165
166 LONG lUi;
167
168 for (lUi = 0; lUi < (LONG)n; lUi++)
169 {
170 Append(asChoices[lUi]);
171 }
172 SetFont(pParent->GetFont());
173 SetSize( nX
174 ,nY
175 ,nWidth
176 ,nHeight
177 );
178 return TRUE;
179} // end of wxListBox::Create
180
181wxListBox::~wxListBox()
182{
183#if wxUSE_OWNER_DRAWN
184 size_t lUiCount = m_aItems.Count();
185
186 while (lUiCount-- != 0)
187 {
188 delete m_aItems[lUiCount];
189 }
190#endif // wxUSE_OWNER_DRAWN
191} // end of wxListBox::~wxListBox
192
193void wxListBox::SetupColours()
194{
195 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
196 SetForegroundColour(GetParent()->GetForegroundColour());
197} // end of wxListBox::SetupColours
198
199// ----------------------------------------------------------------------------
200// implementation of wxListBoxBase methods
201// ----------------------------------------------------------------------------
202
203void wxListBox::DoSetFirstItem(
204 int N
205)
206{
207 wxCHECK_RET( N >= 0 && N < m_nNumItems,
208 wxT("invalid index in wxListBox::SetFirstItem") );
209
210 ::WinSendMsg(GetHwnd(), LM_SETTOPINDEX, MPFROMLONG(N), (MPARAM)0);
211} // end of wxListBox::DoSetFirstItem
212
213void wxListBox::Delete(
214 int N
215)
216{
217 wxCHECK_RET( N >= 0 && N < m_nNumItems,
218 wxT("invalid index in wxListBox::Delete") );
219
220#if wxUSE_OWNER_DRAWN
221 delete m_aItems[N];
222 m_aItems.RemoveAt(N);
223#else // !wxUSE_OWNER_DRAWN
224 if (HasClientObjectData())
225 {
226 delete GetClientObject(N);
227 }
228#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
229
230 ::WinSendMsg(GetHwnd(), LM_DELETEITEM, (MPARAM)N, (MPARAM)0);
231 m_nNumItems--;
232} // end of wxListBox::DoSetFirstItem
233
234int wxListBox::DoAppend(
235 const wxString& rsItem
236)
237{
238 int nIndex = 0;
239 SHORT nIndexType = 0;
240
241 if (m_windowStyle & wxLB_SORT)
242 nIndexType = LIT_SORTASCENDING;
243 else
244 nIndexType = LIT_END;
245 nIndex = (int)::WinSendMsg(GetHwnd(), LM_INSERTITEM, (MPARAM)nIndexType, (MPARAM)rsItem.c_str());
246 m_nNumItems++;
247
248#if wxUSE_OWNER_DRAWN
249 if (m_windowStyle & wxLB_OWNERDRAW)
250 {
251 wxOwnerDrawn* pNewItem = CreateItem(nIndex); // dummy argument
252
253 pNewItem->SetName(rsItem);
254 m_aItems.Add(pNewItem);
255 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE, (MPARAM)((SHORT)nIndex), MPFROMP(pNewItem));
256 pNewItem->SetFont(GetFont());
257 }
258#endif
259 return nIndex;
260} // end of wxListBox::DoAppend
261
262void wxListBox::DoSetItems(
263 const wxArrayString& raChoices
264, void** ppClientData
265)
266{
267 BOOL bHideAndShow = IsShown();
268 int nCount = 0;
269 int i;
270 SHORT nIndexType = 0;
271
272 if (bHideAndShow)
273 {
274 ::WinShowWindow(GetHwnd(), FALSE);
275 }
276 ::WinSendMsg(GetHwnd(), LM_DELETEALL, (MPARAM)0, (MPARAM)0);
277 m_nNumItems = raChoices.GetCount();
278 for (i = 0; i < m_nNumItems; i++)
279 {
280
281 if (m_windowStyle & wxLB_SORT)
282 nIndexType = LIT_SORTASCENDING;
283 else
284 nIndexType = LIT_END;
285 ::WinSendMsg(GetHwnd(), LM_INSERTITEM, (MPARAM)nIndexType, (MPARAM)raChoices[i].c_str());
286
287 if (ppClientData)
288 {
289#if wxUSE_OWNER_DRAWN
290 wxASSERT_MSG(ppClientData[i] == NULL,
291 wxT("Can't use client data with owner-drawn listboxes"));
292#else // !wxUSE_OWNER_DRAWN
293 ::WinSendMsg(WinUtil_GetHwnd(), LM_SETITEMHANDLE, MPFROMLONG(lCount), MPFROMP(ppClientData[i]));
294#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
295 }
296 }
297
298#if wxUSE_OWNER_DRAWN
299 if ( m_windowStyle & wxLB_OWNERDRAW )
300 {
301 //
302 // First delete old items
303 //
304 size_t lUi = m_aItems.Count();
305
306 while (lUi-- != 0)
307 {
308 delete m_aItems[lUi];
309 }
310 m_aItems.Empty();
311
312 //
313 // Then create new ones
314 //
315 for (lUi = 0; lUi < (size_t)m_nNumItems; lUi++)
316 {
317 wxOwnerDrawn* pNewItem = CreateItem(lUi);
318
319 pNewItem->SetName(raChoices[lUi]);
320 m_aItems.Add(pNewItem);
321 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE, MPFROMLONG(lUi), MPFROMP(pNewItem));
322 }
323 }
324#endif // wxUSE_OWNER_DRAWN
325 ::WinShowWindow(GetHwnd(), TRUE);
326} // end of wxListBox::DoSetItems
327
328int wxListBox::FindString(
329 const wxString& rsString
330) const
331{
332 int nPos;
333 LONG lTextLength;
334 PSZ zStr;
335
336
337 for (nPos = 0; nPos < m_nNumItems; nPos++)
338 {
339 lTextLength = LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH, (MPARAM)nPos, (MPARAM)0));
340 zStr = new char[lTextLength + 1];
341 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT, MPFROM2SHORT(nPos, (SHORT)lTextLength), (MPARAM)zStr);
342 if (rsString == (char*)zStr)
343 {
344 delete [] zStr;
345 break;
346 }
347 delete [] zStr;
348 }
349 return nPos;
350} // end of wxListBox::FindString
351
352void wxListBox::Clear()
353{
354#if wxUSE_OWNER_DRAWN
355 size_t lUiCount = m_aItems.Count();
356
357 while (lUiCount-- != 0)
358 {
359 delete m_aItems[lUiCount];
360 }
361
362 m_aItems.Clear();
363#else // !wxUSE_OWNER_DRAWN
364 if (HasClientObjectData())
365 {
366 for (size_t n = 0; n < (size_t)m_lNumItems; n++)
367 {
368 delete GetClientObject(n);
369 }
370 }
371#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
372 ::WinSendMsg(GetHwnd(), LM_DELETEALL, (MPARAM)0, (MPARAM)0);
373
374 m_nNumItems = 0;
375} // end of wxListBox::Clear
376
377void wxListBox::SetSelection(
378 int N
379, bool bSelect
380)
381{
382 wxCHECK_RET( N >= 0 && N < m_nNumItems,
383 wxT("invalid index in wxListBox::SetSelection") );
384 ::WinSendMsg( GetHwnd()
385 ,LM_SELECTITEM
386 ,MPFROMLONG(N)
387 ,(MPARAM)bSelect
388 );
389} // end of wxListBox::SetSelection
390
391bool wxListBox::IsSelected(
392 int N
393) const
394{
395 wxCHECK_MSG( N >= 0 && N < m_nNumItems, FALSE,
396 wxT("invalid index in wxListBox::Selected") );
397
398 LONG lItem;
399
400 lItem = LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYSELECTION, (MPARAM)N, (MPARAM)0));
401 return (lItem != LIT_NONE);
402} // end of wxListBox::IsSelected
403
404wxClientData* wxListBox::DoGetItemClientObject(
405 int n
406) const
407{
408 return (wxClientData *)DoGetItemClientData(n);
409}
410
411void* wxListBox::DoGetItemClientData(
412 int n
413) const
414{
415 wxCHECK_MSG( n >= 0 && n < m_nNumItems, NULL,
416 wxT("invalid index in wxListBox::GetClientData") );
417
418 return((void *)::WinSendMsg(GetHwnd(), LM_QUERYITEMHANDLE, MPFROMLONG(n), (MPARAM)0));
419} // end of wxListBox::DoGetItemClientData
420
421void wxListBox::DoSetItemClientObject(
422 int n
423, wxClientData* pClientData
424)
425{
426 DoSetItemClientData( n
427 ,pClientData
428 );
429} // end of wxListBox::DoSetItemClientObject
430
431void wxListBox::DoSetItemClientData(
432 int n
433, void* pClientData
434)
435{
436 wxCHECK_RET( n >= 0 && n < m_nNumItems,
437 wxT("invalid index in wxListBox::SetClientData") );
438
439#if wxUSE_OWNER_DRAWN
440 if ( m_windowStyle & wxLB_OWNERDRAW )
441 {
442 //
443 // Client data must be pointer to wxOwnerDrawn, otherwise we would crash
444 // in OnMeasure/OnDraw.
445 //
446 wxFAIL_MSG(wxT("Can't use client data with owner-drawn listboxes"));
447 }
448#endif // wxUSE_OWNER_DRAWN
449
450 ::WinSendMsg(GetHwnd(), LM_SETITEMHANDLE, MPFROMLONG(n), MPFROMP(pClientData));
451} // end of wxListBox::DoSetItemClientData
452
453bool wxListBox::HasMultipleSelection() const
454{
455 return (m_windowStyle & wxLB_MULTIPLE) || (m_windowStyle & wxLB_EXTENDED);
456} // end of wxListBox::HasMultipleSelection
457
458int wxListBox::GetSelections(
459 wxArrayInt& raSelections
460) const
461{
462 int nCount = 0;
463 LONG lItem;
464
465
466 raSelections.Empty();
467 if (HasMultipleSelection())
468 {
469 lItem = LONGFROMMR(::WinSendMsg( GetHwnd()
470 ,LM_QUERYSELECTION
471 ,(MPARAM)LIT_FIRST
472 ,(MPARAM)0
473 )
474 );
475 if (lItem != LIT_NONE)
476 {
477 nCount++;
478 while ((lItem = LONGFROMMR(::WinSendMsg( GetHwnd()
479 ,LM_QUERYSELECTION
480 ,(MPARAM)lItem
481 ,(MPARAM)0
482 )
483 )) != LIT_NONE)
484 {
485 nCount++;
486 }
487 raSelections.Alloc(nCount);
488 lItem = LONGFROMMR(::WinSendMsg( GetHwnd()
489 ,LM_QUERYSELECTION
490 ,(MPARAM)LIT_FIRST
491 ,(MPARAM)0
492 )
493 );
494
495 raSelections.Add((int)lItem);
496 while ((lItem = LONGFROMMR(::WinSendMsg( GetHwnd()
497 ,LM_QUERYSELECTION
498 ,(MPARAM)lItem
499 ,(MPARAM)0
500 )
501 )) != LIT_NONE)
502 {
503 raSelections.Add((int)lItem);
504 }
505 return nCount;
506 }
507 return 0;
508 }
509 else // single-selection listbox
510 {
511 lItem = LONGFROMMR(::WinSendMsg( GetHwnd()
512 ,LM_QUERYSELECTION
513 ,(MPARAM)LIT_FIRST
514 ,(MPARAM)0
515 )
516 );
517 raSelections.Add((int)lItem);
518 return 1;
519 }
520 return 0;
521} // end of wxListBox::GetSelections
522
523int wxListBox::GetSelection() const
524{
525 wxCHECK_MSG( !HasMultipleSelection(),
526 -1,
527 wxT("GetSelection() can't be used with multiple-selection "
528 "listboxes, use GetSelections() instead.") );
529
530 return(LONGFROMMR(::WinSendMsg( GetHwnd()
531 ,LM_QUERYSELECTION
532 ,(MPARAM)LIT_FIRST
533 ,(MPARAM)0
534 )
535 ));
536} // end of wxListBox::GetSelection
537
538wxString wxListBox::GetString(
539 int N
540) const
541{
542 LONG lLen = 0;
543 char* zBuf;
544 wxString sResult;
545
546 wxCHECK_MSG( N >= 0 && N < m_nNumItems, "",
547 wxT("invalid index in wxListBox::GetClientData") );
548
549 lLen = LONGFROMMR(::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXTLENGTH, (MPARAM)N, (MPARAM)0));
550 zBuf = new char[lLen + 1];
551 ::WinSendMsg(GetHwnd(), LM_QUERYITEMTEXT, MPFROM2SHORT((SHORT)N, (SHORT)lLen), (MPARAM)zBuf);
552 zBuf[lLen] = '\0';
553 sResult = zBuf;
554 delete [] zBuf;
555 return sResult;
556} // end of wxListBox::GetString
557
558void wxListBox::DoInsertItems(
559 const wxArrayString& asItems
560, int nPos
561)
562{
563 wxCHECK_RET( nPos >= 0 && nPos <= m_nNumItems,
564 wxT("invalid index in wxListBox::InsertItems") );
565
566 int nItems = asItems.GetCount();
567
568 for (int i = 0; i < nItems; i++)
569 ::WinSendMsg(GetHwnd(), LM_INSERTITEM, MPFROMLONG((LONG)(i + nPos)), (MPARAM)asItems[i].c_str());
570 m_nNumItems += nItems;
571} // end of wxListBox::DoInsertItems
572
573void wxListBox::SetString(
574 int N
575, const wxString& rsString
576)
577{
578 wxCHECK_RET( N >= 0 && N < m_nNumItems,
579 wxT("invalid index in wxListBox::SetString") );
580
581 //
582 // Remember the state of the item
583 //
584 bool bWasSelected = IsSelected(N);
585 void* pOldData = NULL;
586 wxClientData* pOldObjData = NULL;
587
588 if (m_clientDataItemsType == wxClientData_Void)
589 pOldData = GetClientData(N);
590 else if (m_clientDataItemsType == wxClientData_Object)
591 pOldObjData = GetClientObject(N);
592
593 //
594 // Delete and recreate it
595 //
596 ::WinSendMsg( GetHwnd()
597 ,LM_DELETEITEM
598 ,(MPARAM)N
599 ,(MPARAM)0
600 );
601
602 int nNewN = N;
603
604 if (N == m_nNumItems - 1)
605 nNewN = -1;
606
607 ::WinSendMsg( GetHwnd()
608 ,LM_INSERTITEM
609 ,(MPARAM)nNewN
610 ,(MPARAM)rsString.c_str()
611 );
612
613 //
614 // Restore the client data
615 //
616 if (pOldData)
617 SetClientData( N
618 ,pOldData
619 );
620 else if (pOldObjData)
621 SetClientObject( N
622 ,pOldObjData
623 );
624
625 //
626 // We may have lost the selection
627 //
628 if (bWasSelected)
629 Select(N);
630
631#if wxUSE_OWNER_DRAWN
632 if (m_windowStyle & wxLB_OWNERDRAW)
633 //
634 // Update item's text
635 //
636 m_aItems[N]->SetName(rsString);
637#endif //USE_OWNER_DRAWN
638} // end of wxListBox::SetString
639
640int wxListBox::GetCount() const
641{
642 return m_nNumItems;
643}
644
645// ----------------------------------------------------------------------------
646// helpers
647// ----------------------------------------------------------------------------
648
649wxSize wxListBox::DoGetBestSize() const
650{
651 //
652 // Find the widest string
653 //
654 int nLine;
655 int nListbox = 0;
656 int nCx;
657 int nCy;
658
659 for (int i = 0; i < m_nNumItems; i++)
660 {
661 wxString vStr(GetString(i));
662
663 GetTextExtent( vStr
664 ,&nLine
665 ,NULL
666 );
667 if (nLine > nListbox)
668 nListbox = nLine;
669 }
670
671 //
672 // Give it some reasonable default value if there are no strings in the
673 // list.
674 //
675 if (nListbox == 0)
676 nListbox = 100;
677
678 //
679 // The listbox should be slightly larger than the widest string
680 //
681 wxGetCharSize( GetHWND()
682 ,&nCx
683 ,&nCy
684 ,(wxFont*)&GetFont()
685 );
686 nListbox += 3 * nCx;
687
688 int hListbox = EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy) * (wxMax(m_nNumItems, 7));
689
690 return wxSize( nListbox
691 ,hListbox
692 );
693} // end of wxListBox::DoGetBestSize
694
695// ----------------------------------------------------------------------------
696// callbacks
697// ----------------------------------------------------------------------------
698
699bool wxListBox::OS2Command(
700 WXUINT uParam
701, WXWORD WXUNUSED(wId))
702{
703 wxEventType eEvtType;
704
705 if (uParam == LN_SELECT)
706 {
707 eEvtType = wxEVT_COMMAND_LISTBOX_SELECTED;
708 }
709 if (uParam == LN_ENTER)
710 {
711 eEvtType = wxEVT_COMMAND_LISTBOX_DOUBLECLICKED;
712 }
713 else
714 {
715 //
716 // Some event we're not interested in
717 //
718 return FALSE;
719 }
720 wxCommandEvent vEvent( eEvtType
721 ,m_windowId
722 );
723
724 vEvent.SetEventObject(this);
725
726 wxArrayInt aSelections;
727 int n;
728 int nCount = GetSelections(aSelections);
729
730 if (nCount > 0)
731 {
732 n = aSelections[0];
733 if (HasClientObjectData())
734 vEvent.SetClientObject(GetClientObject(n));
735 else if ( HasClientUntypedData() )
736 vEvent.SetClientData(GetClientData(n));
737 vEvent.SetString(GetString(n));
738 }
739 else
740 {
741 n = -1;
742 }
743 vEvent.m_commandInt = n;
744 return GetEventHandler()->ProcessEvent(vEvent);
745} // end of wxListBox::OS2Command
746
747// ----------------------------------------------------------------------------
748// wxCheckListBox support
749// ----------------------------------------------------------------------------
750
751#if wxUSE_OWNER_DRAWN
752
753//
754// Drawing
755// -------
756//
757#define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1)
758
759bool wxListBox::OS2OnMeasure(WXMEASUREITEMSTRUCT *item)
760{
761 //
762 // TODO: Get to this eventually
763 //
764 return TRUE;
765}
766
767bool wxListBox::OS2OnDraw(WXDRAWITEMSTRUCT *item)
768{
769 //
770 // TODO: Get to this eventually
771 //
772 return FALSE;
773}
774#endif // ndef for wxUSE_OWNER_DRAWN
775
776#endif // ndef for wxUSE_LISTBOX
777