Allow unsetting wxMenuItem as start of radio group too.
[wxWidgets.git] / src / osx / choice_osx.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/choice_osx.cpp
3 // Purpose: wxChoice
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #if wxUSE_CHOICE
15
16 #include "wx/choice.h"
17
18 #ifndef WX_PRECOMP
19 #include "wx/menu.h"
20 #include "wx/dcclient.h"
21 #endif
22
23 #include "wx/osx/private.h"
24
25 wxChoice::~wxChoice()
26 {
27 if ( HasClientObjectData() )
28 {
29 unsigned int i, max = GetCount();
30
31 for ( i = 0; i < max; ++i )
32 delete GetClientObject( i );
33 }
34 delete m_popUpMenu;
35 }
36
37 bool wxChoice::Create(wxWindow *parent,
38 wxWindowID id,
39 const wxPoint& pos,
40 const wxSize& size,
41 const wxArrayString& choices,
42 long style,
43 const wxValidator& validator,
44 const wxString& name )
45 {
46 if ( !Create( parent, id, pos, size, 0, NULL, style, validator, name ) )
47 return false;
48
49 Append( choices );
50
51 if ( !choices.empty() )
52 SetSelection( 0 );
53
54 SetInitialSize( size );
55
56 return true;
57 }
58
59 bool wxChoice::Create(wxWindow *parent,
60 wxWindowID id,
61 const wxPoint& pos,
62 const wxSize& size,
63 int n,
64 const wxString choices[],
65 long style,
66 const wxValidator& validator,
67 const wxString& name )
68 {
69 DontCreatePeer();
70
71 if ( !wxChoiceBase::Create( parent, id, pos, size, style, validator, name ) )
72 return false;
73
74 m_popUpMenu = new wxMenu();
75 m_popUpMenu->SetNoEventsMode(true);
76
77 SetPeer(wxWidgetImpl::CreateChoice( this, parent, id, m_popUpMenu, pos, size, style, GetExtraStyle() ));
78
79 MacPostControlCreate( pos, size );
80
81 #if !wxUSE_STD_CONTAINERS
82 if ( style & wxCB_SORT )
83 // autosort
84 m_strings = wxArrayString( 1 );
85 #endif
86
87 Append(n, choices);
88
89 // Set the first item as being selected
90 if (n > 0)
91 SetSelection( 0 );
92
93 // Needed because it is a wxControlWithItems
94 SetInitialSize( size );
95
96 return true;
97 }
98
99 // ----------------------------------------------------------------------------
100 // adding/deleting items to/from the list
101 // ----------------------------------------------------------------------------
102
103 void wxChoice::DoAfterItemCountChange()
104 {
105 InvalidateBestSize();
106
107 GetPeer()->SetMaximum( GetCount() );
108 }
109
110 int wxChoice::DoInsertItems(const wxArrayStringsAdapter & items,
111 unsigned int pos,
112 void **clientData, wxClientDataType type)
113 {
114 const unsigned int numItems = items.GetCount();
115 for( unsigned int i = 0; i < numItems; ++i, ++pos )
116 {
117 unsigned int idx;
118
119 #if wxUSE_STD_CONTAINERS
120 if ( IsSorted() )
121 {
122 wxArrayString::iterator
123 insertPoint = std::lower_bound( m_strings.begin(), m_strings.end(), items[i] );
124 idx = insertPoint - m_strings.begin();
125 m_strings.insert( insertPoint, items[i] );
126 }
127 else
128 #endif // wxUSE_STD_CONTAINERS
129 {
130 idx = pos;
131 m_strings.Insert( items[i], idx );
132 }
133
134 wxString text = items[i];
135 if (text == wxEmptyString)
136 text = " "; // menu items can't have empty labels
137 m_popUpMenu->Insert( idx, i+1, text );
138 m_datas.Insert( NULL, idx );
139 AssignNewItemClientData(idx, clientData, i, type);
140 }
141
142 DoAfterItemCountChange();
143
144 return pos - 1;
145 }
146
147 void wxChoice::DoDeleteOneItem(unsigned int n)
148 {
149 wxCHECK_RET( IsValid(n) , wxT("wxChoice::Delete: invalid index") );
150
151 if ( HasClientObjectData() )
152 delete GetClientObject( n );
153
154 m_popUpMenu->Delete( m_popUpMenu->FindItemByPosition( n ) );
155
156 m_strings.RemoveAt( n ) ;
157 m_datas.RemoveAt( n ) ;
158
159 DoAfterItemCountChange();
160 }
161
162 void wxChoice::DoClear()
163 {
164 for ( unsigned int i = 0 ; i < GetCount() ; i++ )
165 {
166 m_popUpMenu->Delete( m_popUpMenu->FindItemByPosition( 0 ) );
167 }
168
169 m_strings.Empty() ;
170 m_datas.Empty() ;
171
172 DoAfterItemCountChange();
173 }
174
175 // ----------------------------------------------------------------------------
176 // selection
177 // ----------------------------------------------------------------------------
178 int wxChoice::GetSelection() const
179 {
180 return GetPeer()->GetValue();
181 }
182
183 void wxChoice::SetSelection( int n )
184 {
185 GetPeer()->SetValue( n );
186 }
187
188 // ----------------------------------------------------------------------------
189 // string list functions
190 // ----------------------------------------------------------------------------
191
192 unsigned int wxChoice::GetCount() const
193 {
194 return m_strings.GetCount() ;
195 }
196
197 int wxChoice::FindString( const wxString& s, bool bCase ) const
198 {
199 #if !wxUSE_STD_CONTAINERS
200 // Avoid assert for non-default args passed to sorted array Index
201 if ( IsSorted() )
202 bCase = true;
203 #endif
204
205 return m_strings.Index( s , bCase ) ;
206 }
207
208 void wxChoice::SetString(unsigned int n, const wxString& s)
209 {
210 wxCHECK_RET( IsValid(n), wxT("wxChoice::SetString(): invalid index") );
211
212 m_strings[n] = s ;
213
214 m_popUpMenu->FindItemByPosition( n )->SetItemLabel( s ) ;
215 }
216
217 wxString wxChoice::GetString(unsigned int n) const
218 {
219 wxCHECK_MSG( IsValid(n), wxEmptyString, wxT("wxChoice::GetString(): invalid index") );
220
221 return m_strings[n] ;
222 }
223
224 // ----------------------------------------------------------------------------
225 // client data
226 // ----------------------------------------------------------------------------
227 void wxChoice::DoSetItemClientData(unsigned int n, void* clientData)
228 {
229 m_datas[n] = (char*)clientData ;
230 }
231
232 void * wxChoice::DoGetItemClientData(unsigned int n) const
233 {
234 return (void *)m_datas[n];
235 }
236
237 bool wxChoice::OSXHandleClicked( double WXUNUSED(timestampsec) )
238 {
239 SendSelectionChangedEvent(wxEVT_CHOICE);
240
241 return true ;
242 }
243
244 wxSize wxChoice::DoGetBestSize() const
245 {
246 // We use the base window size for the height (which is wrong as it doesn't
247 // take the font into account -- TODO) and add some margins to the width
248 // computed by the base class method to account for the arrow.
249 const int lbHeight = wxWindow::DoGetBestSize().y;
250
251 return wxSize(wxChoiceBase::DoGetBestSize().x + 2*lbHeight + GetCharWidth(),
252 lbHeight);
253 }
254
255 #endif // wxUSE_CHOICE