]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/choice.cpp
Add middle-item click support.
[wxWidgets.git] / src / mac / carbon / choice.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/choice.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/mac/uma.h"
24
25 extern MenuHandle NewUniqueMenu() ;
26
27 IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
28
29
30 wxChoice::~wxChoice()
31 {
32 if ( HasClientObjectData() )
33 {
34 unsigned int i, max = GetCount();
35
36 for ( i = 0; i < max; ++i )
37 delete GetClientObject( i );
38 }
39
40 // DeleteMenu( m_macPopUpMenuId ) ;
41 // DisposeMenu( m_macPopUpMenuHandle ) ;
42 }
43
44 bool wxChoice::Create(wxWindow *parent,
45 wxWindowID id,
46 const wxPoint& pos,
47 const wxSize& size,
48 const wxArrayString& choices,
49 long style,
50 const wxValidator& validator,
51 const wxString& name )
52 {
53 wxCArrayString chs( choices );
54
55 return Create(
56 parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
57 style, validator, name );
58 }
59
60 bool wxChoice::Create(wxWindow *parent,
61 wxWindowID id,
62 const wxPoint& pos,
63 const wxSize& size,
64 int n,
65 const wxString choices[],
66 long style,
67 const wxValidator& validator,
68 const wxString& name )
69 {
70 m_macIsUserPane = false;
71
72 if ( !wxChoiceBase::Create( parent, id, pos, size, style, validator, name ) )
73 return false;
74
75 Rect bounds = wxMacGetBoundsForControl( this , pos , size );
76
77 m_peer = new wxMacControl( this ) ;
78 OSStatus err = CreatePopupButtonControl(
79 MAC_WXHWND(parent->MacGetTopLevelWindowRef()) , &bounds , CFSTR("") ,
80 -12345 , false /* no variable width */ , 0 , 0 , 0 , m_peer->GetControlRefAddr() );
81 verify_noerr( err );
82
83 m_macPopUpMenuHandle = NewUniqueMenu() ;
84 m_peer->SetData<MenuHandle>( kControlNoPart , kControlPopupButtonMenuHandleTag , (MenuHandle) m_macPopUpMenuHandle ) ;
85 m_peer->SetValueAndRange( n > 0 ? 1 : 0 , 0 , 0 );
86 MacPostControlCreate( pos, size );
87
88 #if !wxUSE_STL
89 if ( style & wxCB_SORT )
90 // autosort
91 m_strings = wxArrayString( 1 );
92 #endif
93
94 for ( int i = 0; i < n; i++ )
95 {
96 Append( choices[i] );
97 }
98
99 // Set the first item as being selected
100 if (n > 0)
101 SetSelection( 0 );
102
103 // Needed because it is a wxControlWithItems
104 SetInitialSize( size );
105
106 return true;
107 }
108
109 // ----------------------------------------------------------------------------
110 // adding/deleting items to/from the list
111 // ----------------------------------------------------------------------------
112 int wxChoice::DoAppend( const wxString& item )
113 {
114 #if wxUSE_STL
115 wxArrayString::iterator insertPoint;
116 unsigned int index;
117
118 if (GetWindowStyle() & wxCB_SORT)
119 {
120 insertPoint = std::lower_bound( m_strings.begin(), m_strings.end(), item );
121 index = insertPoint - m_strings.begin();
122 }
123 else
124 {
125 insertPoint = m_strings.end();
126 index = m_strings.size();
127 }
128
129 m_strings.insert( insertPoint, item );
130 #else
131 unsigned int index = m_strings.Add( item );
132 #endif
133
134 m_datas.Insert( NULL , index );
135 UMAInsertMenuItem( MAC_WXHMENU( m_macPopUpMenuHandle ), item, m_font.GetEncoding(), index );
136 DoSetItemClientData( index, NULL );
137 m_peer->SetMaximum( GetCount() );
138
139 return index;
140 }
141
142 int wxChoice::DoInsert( const wxString& item, unsigned int pos )
143 {
144 wxCHECK_MSG( !(GetWindowStyle() & wxCB_SORT), -1, wxT("wxChoice::DoInsert: can't insert into sorted list") );
145 wxCHECK_MSG( IsValidInsert(pos), -1, wxT("wxChoice::DoInsert: invalid index") );
146
147 if (pos == GetCount())
148 return DoAppend( item );
149
150 UMAInsertMenuItem( MAC_WXHMENU( m_macPopUpMenuHandle ), item, m_font.GetEncoding(), pos );
151 m_strings.Insert( item, pos );
152 m_datas.Insert( NULL, pos );
153 DoSetItemClientData( pos, NULL );
154 m_peer->SetMaximum( GetCount() );
155
156 return pos;
157 }
158
159 void wxChoice::Delete(unsigned int n)
160 {
161 wxCHECK_RET( IsValid(n) , wxT("wxChoice::Delete: invalid index") );
162
163 if ( HasClientObjectData() )
164 delete GetClientObject( n );
165
166 ::DeleteMenuItem( MAC_WXHMENU(m_macPopUpMenuHandle) , n + 1 ) ;
167 m_strings.RemoveAt( n ) ;
168 m_datas.RemoveAt( n ) ;
169 m_peer->SetMaximum( GetCount() ) ;
170 }
171
172 void wxChoice::Clear()
173 {
174 FreeData();
175 for ( unsigned int i = 0 ; i < GetCount() ; i++ )
176 {
177 ::DeleteMenuItem( MAC_WXHMENU(m_macPopUpMenuHandle) , 1 ) ;
178 }
179
180 m_strings.Empty() ;
181 m_datas.Empty() ;
182 m_peer->SetMaximum( 0 ) ;
183 }
184
185 void wxChoice::FreeData()
186 {
187 if ( HasClientObjectData() )
188 {
189 unsigned int count = GetCount();
190 for ( unsigned int n = 0; n < count; n++ )
191 {
192 delete GetClientObject( n );
193 }
194 }
195 }
196
197 // ----------------------------------------------------------------------------
198 // selection
199 // ----------------------------------------------------------------------------
200 int wxChoice::GetSelection() const
201 {
202 return m_peer->GetValue() - 1 ;
203 }
204
205 void wxChoice::SetSelection( int n )
206 {
207 m_peer->SetValue( n + 1 ) ;
208 }
209
210 // ----------------------------------------------------------------------------
211 // string list functions
212 // ----------------------------------------------------------------------------
213
214 unsigned int wxChoice::GetCount() const
215 {
216 return m_strings.GetCount() ;
217 }
218
219 int wxChoice::FindString( const wxString& s, bool bCase ) const
220 {
221 #if !wxUSE_STL
222 // Avoid assert for non-default args passed to sorted array Index
223 if ( HasFlag(wxCB_SORT) )
224 bCase = true;
225 #endif
226
227 return m_strings.Index( s , bCase ) ;
228 }
229
230 void wxChoice::SetString(unsigned int n, const wxString& s)
231 {
232 wxCHECK_RET( IsValid(n), wxT("wxChoice::SetString(): invalid index") );
233
234 m_strings[n] = s ;
235
236 // apple menu pos is 1-based
237 UMASetMenuItemText( MAC_WXHMENU(m_macPopUpMenuHandle) , n + 1 , s , wxFont::GetDefaultEncoding() ) ;
238 }
239
240 wxString wxChoice::GetString(unsigned int n) const
241 {
242 wxCHECK_MSG( IsValid(n), wxEmptyString, wxT("wxChoice::GetString(): invalid index") );
243
244 return m_strings[n] ;
245 }
246
247 // ----------------------------------------------------------------------------
248 // client data
249 // ----------------------------------------------------------------------------
250 void wxChoice::DoSetItemClientData(unsigned int n, void* clientData)
251 {
252 wxCHECK_RET( IsValid(n), wxT("wxChoice::DoSetItemClientData: invalid index") );
253
254 m_datas[n] = (char*)clientData ;
255 }
256
257 void * wxChoice::DoGetItemClientData(unsigned int n) const
258 {
259 wxCHECK_MSG( IsValid(n), NULL, wxT("wxChoice::DoGetClientData: invalid index") );
260
261 return (void *)m_datas[n];
262 }
263
264 void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
265 {
266 DoSetItemClientData(n, clientData);
267 }
268
269 wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const
270 {
271 return (wxClientData*)DoGetItemClientData( n ) ;
272 }
273
274 wxInt32 wxChoice::MacControlHit( WXEVENTHANDLERREF WXUNUSED(handler) , WXEVENTREF WXUNUSED(event) )
275 {
276 wxCommandEvent event( wxEVT_COMMAND_CHOICE_SELECTED, m_windowId );
277
278 // actually n should be made sure by the os to be a valid selection, but ...
279 int n = GetSelection();
280 if ( n > -1 )
281 {
282 event.SetInt( n );
283 event.SetString( GetStringSelection() );
284 event.SetEventObject( this );
285
286 if ( HasClientObjectData() )
287 event.SetClientObject( GetClientObject( n ) );
288 else if ( HasClientUntypedData() )
289 event.SetClientData( GetClientData( n ) );
290
291 ProcessCommand( event );
292 }
293
294 return noErr ;
295 }
296
297 wxSize wxChoice::DoGetBestSize() const
298 {
299 int lbWidth = GetCount() > 0 ? 20 : 100; // some defaults
300 int lbHeight = 20;
301 int wLine;
302
303 #if TARGET_CARBON
304 SInt32 metric ;
305
306 GetThemeMetric( kThemeMetricPopupButtonHeight , &metric );
307 lbHeight = metric ;
308 #endif
309
310 {
311 #if wxMAC_USE_CORE_GRAPHICS
312 wxClientDC dc(const_cast<wxChoice*>(this));
313 #else
314 wxMacPortStateHelper st( UMAGetWindowPort( (WindowRef) MacGetTopLevelWindowRef() ) ) ;
315 if ( m_font.Ok() )
316 {
317 ::TextFont( m_font.MacGetFontNum() ) ;
318 ::TextSize( m_font.MacGetFontSize() ) ;
319 ::TextFace( m_font.MacGetFontStyle() ) ;
320 }
321 else
322 {
323 ::TextFont( kFontIDMonaco ) ;
324 ::TextSize( 9 ) ;
325 ::TextFace( 0 ) ;
326 }
327 #endif
328 // Find the widest line
329 for(unsigned int i = 0; i < GetCount(); i++)
330 {
331 wxString str(GetString(i));
332 #if wxMAC_USE_CORE_GRAPHICS
333 wxCoord width, height ;
334 dc.GetTextExtent( str , &width, &height);
335 wLine = width ;
336 #else
337 #if wxUSE_UNICODE
338 Point bounds = { 0, 0 } ;
339 SInt16 baseline ;
340
341 ::GetThemeTextDimensions( wxMacCFStringHolder( str , m_font.GetEncoding() ) ,
342 kThemeCurrentPortFont,
343 kThemeStateActive,
344 false,
345 &bounds,
346 &baseline );
347
348 wLine = bounds.h ;
349 #else
350 wLine = ::TextWidth( str.c_str() , 0 , str.length() ) ;
351 #endif
352 #endif
353 lbWidth = wxMax( lbWidth, wLine ) ;
354 }
355
356 // Add room for the popup arrow
357 lbWidth += 2 * lbHeight ;
358 #if wxMAC_USE_CORE_GRAPHICS
359 wxCoord width, height ;
360 dc.GetTextExtent( wxT("X"), &width, &height);
361 int cx = width ;
362 lbHeight += 4;
363 #else
364 // And just a bit more
365 int cx = ::TextWidth( "X" , 0 , 1 ) ;
366 #endif
367 lbWidth += cx ;
368 }
369
370 return wxSize( lbWidth, lbHeight );
371 }
372
373 #endif // wxUSE_CHOICE