]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/combobox.mm
No changes, just use wxRecursionGuard instead of manual boolean flag.
[wxWidgets.git] / src / osx / cocoa / combobox.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/combobox.mm
3 // Purpose: wxChoice
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // Copyright: (c) Stefan Csomor
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #include "wx/wxprec.h"
12
13 #if wxUSE_COMBOBOX
14
15 #include "wx/combobox.h"
16 #include "wx/evtloop.h"
17
18 #ifndef WX_PRECOMP
19 #include "wx/menu.h"
20 #include "wx/dcclient.h"
21 #endif
22
23 #include "wx/osx/cocoa/private/textimpl.h"
24
25 // work in progress
26
27 @interface wxNSTableDataSource : NSObject wxOSX_10_6_AND_LATER(<NSComboBoxDataSource>)
28 {
29 wxNSComboBoxControl* impl;
30 }
31
32 - (NSInteger)numberOfItemsInComboBox:(NSComboBox *)aComboBox;
33 - (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(NSInteger)index;
34
35 @end
36
37
38 @implementation wxNSComboBox
39
40 + (void)initialize
41 {
42 static BOOL initialized = NO;
43 if (!initialized)
44 {
45 initialized = YES;
46 wxOSXCocoaClassAddWXMethods( self );
47 }
48 }
49
50 - (void) dealloc
51 {
52 [fieldEditor release];
53 [super dealloc];
54 }
55
56 // Over-riding NSComboBox onKeyDown method doesn't work for key events.
57 // Ensure that we can use our own wxNSTextFieldEditor to catch key events.
58 // See windowWillReturnFieldEditor in nonownedwnd.mm.
59 // Key events will be caught and handled via wxNSTextFieldEditor onkey...
60 // methods in textctrl.mm.
61
62 - (void) setFieldEditor:(wxNSTextFieldEditor*) editor
63 {
64 if ( editor != fieldEditor )
65 {
66 [editor retain];
67 [fieldEditor release];
68 fieldEditor = editor;
69 }
70 }
71
72 - (wxNSTextFieldEditor*) fieldEditor
73 {
74 return fieldEditor;
75 }
76
77 - (void)controlTextDidChange:(NSNotification *)aNotification
78 {
79 wxUnusedVar(aNotification);
80 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
81 if ( impl && impl->ShouldSendEvents() )
82 {
83 wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer();
84 if ( wxpeer ) {
85 wxCommandEvent event(wxEVT_TEXT, wxpeer->GetId());
86 event.SetEventObject( wxpeer );
87 event.SetString( static_cast<wxComboBox*>(wxpeer)->GetValue() );
88 wxpeer->HandleWindowEvent( event );
89 }
90 }
91 }
92
93 - (void)comboBoxSelectionDidChange:(NSNotification *)notification
94 {
95 wxUnusedVar(notification);
96 wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
97 if ( impl && impl->ShouldSendEvents())
98 {
99 wxComboBox* wxpeer = static_cast<wxComboBox*>(impl->GetWXPeer());
100 if ( wxpeer ) {
101 const int sel = wxpeer->GetSelection();
102
103 wxCommandEvent event(wxEVT_COMBOBOX, wxpeer->GetId());
104 event.SetEventObject( wxpeer );
105 event.SetInt( sel );
106 event.SetString( wxpeer->GetString(sel) );
107 // For some reason, wxComboBox::GetValue will not return the newly selected item
108 // while we're inside this callback, so use AddPendingEvent to make sure
109 // GetValue() returns the right value.
110
111 wxpeer->GetEventHandler()->AddPendingEvent( event );
112
113 }
114 }
115 }
116 @end
117
118 wxNSComboBoxControl::wxNSComboBoxControl( wxComboBox *wxPeer, WXWidget w )
119 : wxNSTextFieldControl(wxPeer, wxPeer, w)
120 {
121 m_comboBox = (NSComboBox*)w;
122 }
123
124 wxNSComboBoxControl::~wxNSComboBoxControl()
125 {
126 }
127
128 void wxNSComboBoxControl::mouseEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
129 {
130 // NSComboBox has its own event loop, which reacts very badly to our synthetic
131 // events used to signal when a wxEvent is posted, so during that time we switch
132 // the wxEventLoop::WakeUp implementation to a lower-level version
133
134 bool reset = false;
135 wxEventLoop* const loop = (wxEventLoop*) wxEventLoopBase::GetActive();
136
137 if ( loop != NULL && [event type] == NSLeftMouseDown )
138 {
139 reset = true;
140 loop->OSXUseLowLevelWakeup(true);
141 }
142
143 wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
144 superimpl(slf, (SEL)_cmd, event);
145
146 if ( reset )
147 {
148 loop->OSXUseLowLevelWakeup(false);
149 }
150 }
151
152 int wxNSComboBoxControl::GetSelectedItem() const
153 {
154 return [m_comboBox indexOfSelectedItem];
155 }
156
157 void wxNSComboBoxControl::SetSelectedItem(int item)
158 {
159 SendEvents(false);
160
161 if ( item != wxNOT_FOUND )
162 {
163 wxASSERT_MSG( item >= 0 && item < [m_comboBox numberOfItems],
164 "Inavlid item index." );
165 [m_comboBox selectItemAtIndex: item];
166 }
167 else // remove current selection (if we have any)
168 {
169 const int sel = GetSelectedItem();
170 if ( sel != wxNOT_FOUND )
171 [m_comboBox deselectItemAtIndex:sel];
172 }
173
174 SendEvents(true);
175 }
176
177 int wxNSComboBoxControl::GetNumberOfItems() const
178 {
179 return [m_comboBox numberOfItems];
180 }
181
182 void wxNSComboBoxControl::InsertItem(int pos, const wxString& item)
183 {
184 [m_comboBox insertItemWithObjectValue:wxCFStringRef( item , m_wxPeer->GetFont().GetEncoding() ).AsNSString() atIndex:pos];
185 }
186
187 void wxNSComboBoxControl::RemoveItem(int pos)
188 {
189 SendEvents(false);
190 [m_comboBox removeItemAtIndex:pos];
191 SendEvents(true);
192 }
193
194 void wxNSComboBoxControl::Clear()
195 {
196 SendEvents(false);
197 [m_comboBox removeAllItems];
198 [m_comboBox setStringValue:@""];
199 SendEvents(true);
200 }
201
202 wxString wxNSComboBoxControl::GetStringAtIndex(int pos) const
203 {
204 return wxCFStringRef::AsString([m_comboBox itemObjectValueAtIndex:pos], m_wxPeer->GetFont().GetEncoding());
205 }
206
207 int wxNSComboBoxControl::FindString(const wxString& text) const
208 {
209 NSInteger nsresult = [m_comboBox indexOfItemWithObjectValue:wxCFStringRef( text , m_wxPeer->GetFont().GetEncoding() ).AsNSString()];
210
211 int result;
212 if (nsresult == NSNotFound)
213 result = wxNOT_FOUND;
214 else
215 result = (int) nsresult;
216 return result;
217 }
218
219 void wxNSComboBoxControl::Popup()
220 {
221 id ax = NSAccessibilityUnignoredDescendant(m_comboBox);
222 [ax accessibilitySetValue: [NSNumber numberWithBool: YES] forAttribute: NSAccessibilityExpandedAttribute];
223 }
224
225 void wxNSComboBoxControl::Dismiss()
226 {
227 id ax = NSAccessibilityUnignoredDescendant(m_comboBox);
228 [ax accessibilitySetValue: [NSNumber numberWithBool: NO] forAttribute: NSAccessibilityExpandedAttribute];
229 }
230
231 void wxNSComboBoxControl::SetEditable(bool editable)
232 {
233 // TODO: unfortunately this does not work, setEditable just means the same as CB_READONLY
234 // I don't see a way to access the text field directly
235
236 // Behavior NONE <- SELECTECTABLE
237 [m_comboBox setEditable:editable];
238 }
239
240 wxWidgetImplType* wxWidgetImpl::CreateComboBox( wxComboBox* wxpeer,
241 wxWindowMac* WXUNUSED(parent),
242 wxWindowID WXUNUSED(id),
243 wxMenu* WXUNUSED(menu),
244 const wxPoint& pos,
245 const wxSize& size,
246 long style,
247 long WXUNUSED(extraStyle))
248 {
249 NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
250 wxNSComboBox* v = [[wxNSComboBox alloc] initWithFrame:r];
251 if (style & wxCB_READONLY)
252 [v setEditable:NO];
253 wxNSComboBoxControl* c = new wxNSComboBoxControl( wxpeer, v );
254 return c;
255 }
256
257 wxSize wxComboBox::DoGetBestSize() const
258 {
259 int lbWidth = GetCount() > 0 ? 20 : 100; // some defaults
260 wxSize baseSize = wxWindow::DoGetBestSize();
261 int lbHeight = baseSize.y;
262 int wLine;
263
264 {
265 wxClientDC dc(const_cast<wxComboBox*>(this));
266
267 // Find the widest line
268 for(unsigned int i = 0; i < GetCount(); i++)
269 {
270 wxString str(GetString(i));
271
272 wxCoord width, height ;
273 dc.GetTextExtent( str , &width, &height);
274 wLine = width ;
275
276 lbWidth = wxMax( lbWidth, wLine ) ;
277 }
278
279 // Add room for the popup arrow
280 lbWidth += 2 * lbHeight ;
281 }
282
283 return wxSize( lbWidth, lbHeight );
284 }
285
286 #endif // wxUSE_COMBOBOX