]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/combobox.cpp
disable code because of OS bug, fixes #12478, fixes #12554
[wxWidgets.git] / src / osx / carbon / combobox.cpp
CommitLineData
489468fe 1/////////////////////////////////////////////////////////////////////////////
524c47aa 2// Name: src/osx/carbon/combobox.cpp
489468fe
SC
3// Purpose: wxComboBox class
4// Author: Stefan Csomor, Dan "Bud" Keith (composite combobox)
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
c84030e0 14#if wxUSE_COMBOBOX && wxOSX_USE_CARBON
489468fe
SC
15
16#include "wx/combobox.h"
17
18#ifndef WX_PRECOMP
19 #include "wx/button.h"
20 #include "wx/menu.h"
21 #include "wx/containr.h"
22 #include "wx/toplevel.h"
23 #include "wx/textctrl.h"
24#endif
25
524c47aa 26#include "wx/osx/private.h"
489468fe
SC
27
28IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
29
30WX_DELEGATE_TO_CONTROL_CONTAINER(wxComboBox, wxControl)
31
32BEGIN_EVENT_TABLE(wxComboBox, wxControl)
33 WX_EVENT_TABLE_CONTROL_CONTAINER(wxComboBox)
34END_EVENT_TABLE()
35
36
489468fe
SC
37// ----------------------------------------------------------------------------
38// constants
39// ----------------------------------------------------------------------------
40
41// the margin between the text control and the choice
42// margin should be bigger on OS X due to blue highlight
43// around text control.
44static const wxCoord MARGIN = 4;
45// this is the border a focus rect on OSX is needing
46static const int TEXTFOCUSBORDER = 3 ;
47
48
49// ----------------------------------------------------------------------------
50// wxComboBoxText: text control forwards events to combobox
51// ----------------------------------------------------------------------------
52
53class wxComboBoxText : public wxTextCtrl
54{
55public:
56 wxComboBoxText( wxComboBox * cb )
57 : wxTextCtrl( cb , 1 )
58 {
59 m_cb = cb;
489468fe
SC
60 }
61
62protected:
63 void OnChar( wxKeyEvent& event )
64 {
65 // Allows processing the tab key to go to the next control
66 if (event.GetKeyCode() == WXK_TAB)
67 {
68 wxNavigationKeyEvent NavEvent;
69 NavEvent.SetEventObject(this);
70 NavEvent.SetDirection(true);
71 NavEvent.SetWindowChange(false);
72
73 // Get the parent of the combo and have it process the navigation?
74 if (m_cb->GetParent()->HandleWindowEvent(NavEvent))
75 return;
76 }
77
78 // send the event to the combobox class in case the user has bound EVT_CHAR
79 wxKeyEvent kevt(event);
80 kevt.SetEventObject(m_cb);
81 if (m_cb->HandleWindowEvent(kevt))
82 // If the event was handled and not skipped then we're done
83 return;
84
85 if ( event.GetKeyCode() == WXK_RETURN )
86 {
87 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_cb->GetId());
88 event.SetString( GetValue() );
89 event.SetInt( m_cb->GetSelection() );
90 event.SetEventObject( m_cb );
91
92 // This will invoke the dialog default action,
93 // such as the clicking the default button.
94 if (!m_cb->HandleWindowEvent( event ))
95 {
96 wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
97 if ( tlw && tlw->GetDefaultItem() )
98 {
99 wxButton *def = wxDynamicCast(tlw->GetDefaultItem(), wxButton);
100 if ( def && def->IsEnabled() )
101 {
102 wxCommandEvent event( wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
103 event.SetEventObject(def);
104 def->Command(event);
105 }
106 }
107
108 return;
109 }
110 }
111
112 event.Skip();
113 }
114
115 void OnKeyUp( wxKeyEvent& event )
116 {
117 event.SetEventObject(m_cb);
118 event.SetId(m_cb->GetId());
119 if (! m_cb->HandleWindowEvent(event))
120 event.Skip();
121 }
122
123 void OnKeyDown( wxKeyEvent& event )
124 {
125 event.SetEventObject(m_cb);
126 event.SetId(m_cb->GetId());
127 if (! m_cb->HandleWindowEvent(event))
128 event.Skip();
129 }
130
131 void OnText( wxCommandEvent& event )
132 {
133 event.SetEventObject(m_cb);
134 event.SetId(m_cb->GetId());
135 if (! m_cb->HandleWindowEvent(event))
136 event.Skip();
137 }
138
9044b125
SC
139 void OnFocus( wxFocusEvent& event )
140 {
141 // in case the textcontrol gets the focus we propagate
142 // it to the parent's handlers.
143 wxFocusEvent evt2(event.GetEventType(),m_cb->GetId());
144 evt2.SetEventObject(m_cb);
145 m_cb->GetEventHandler()->ProcessEvent(evt2);
146
147 event.Skip();
148 }
03647350 149
489468fe
SC
150private:
151 wxComboBox *m_cb;
152
153 DECLARE_EVENT_TABLE()
154};
155
156BEGIN_EVENT_TABLE(wxComboBoxText, wxTextCtrl)
157 EVT_KEY_DOWN(wxComboBoxText::OnKeyDown)
158 EVT_CHAR(wxComboBoxText::OnChar)
159 EVT_KEY_UP(wxComboBoxText::OnKeyUp)
9044b125
SC
160 EVT_SET_FOCUS(wxComboBoxText::OnFocus)
161 EVT_KILL_FOCUS(wxComboBoxText::OnFocus)
489468fe
SC
162 EVT_TEXT(wxID_ANY, wxComboBoxText::OnText)
163END_EVENT_TABLE()
164
165class wxComboBoxChoice : public wxChoice
166{
167public:
168 wxComboBoxChoice( wxComboBox *cb, int style )
169 : wxChoice( cb , 1 , wxDefaultPosition , wxDefaultSize , 0 , NULL , style & (wxCB_SORT) )
170 {
171 m_cb = cb;
172 }
173
174 int GetPopupWidth() const
175 {
176 switch ( GetWindowVariant() )
177 {
178 case wxWINDOW_VARIANT_NORMAL :
179 case wxWINDOW_VARIANT_LARGE :
180 return 24 ;
181
182 default :
183 return 21 ;
184 }
185 }
186
187protected:
188 void OnChoice( wxCommandEvent& e )
189 {
190 wxString s = e.GetString();
191
192 m_cb->DelegateChoice( s );
193 wxCommandEvent event2(wxEVT_COMMAND_COMBOBOX_SELECTED, m_cb->GetId() );
194 event2.SetInt(m_cb->GetSelection());
195 event2.SetEventObject(m_cb);
196 event2.SetString(m_cb->GetStringSelection());
197 m_cb->ProcessCommand(event2);
198
199 // For consistency with MSW and GTK, also send a text updated event
200 // After all, the text is updated when a selection is made
201 wxCommandEvent TextEvent( wxEVT_COMMAND_TEXT_UPDATED, m_cb->GetId() );
202 TextEvent.SetString( m_cb->GetStringSelection() );
203 TextEvent.SetEventObject( m_cb );
204 m_cb->ProcessCommand( TextEvent );
205 }
206
207 virtual wxSize DoGetBestSize() const
208 {
209 wxSize sz = wxChoice::DoGetBestSize() ;
210 if (! m_cb->HasFlag(wxCB_READONLY) )
211 sz.x = GetPopupWidth() ;
212
213 return sz ;
214 }
215
216private:
217 wxComboBox *m_cb;
218
219 friend class wxComboBox;
220
221 DECLARE_EVENT_TABLE()
222};
223
224BEGIN_EVENT_TABLE(wxComboBoxChoice, wxChoice)
225 EVT_CHOICE(wxID_ANY, wxComboBoxChoice::OnChoice)
226END_EVENT_TABLE()
227
228wxComboBox::~wxComboBox()
229{
230 // delete the controls now, don't leave them alive even though they would
231 // still be eventually deleted by our parent - but it will be too late, the
232 // user code expects them to be gone now
5276b0a5
VZ
233 wxDELETE(m_text);
234 wxDELETE(m_choice);
489468fe
SC
235}
236
237// ----------------------------------------------------------------------------
238// geometry
239// ----------------------------------------------------------------------------
240
241wxSize wxComboBox::DoGetBestSize() const
242{
243 if (!m_choice && !m_text)
244 return GetSize();
245
246 wxSize size = m_choice->GetBestSize();
247
248 if ( m_text != NULL )
249 {
250 wxSize sizeText = m_text->GetBestSize();
d33e45f1
SC
251 if (sizeText.y + 2 * TEXTFOCUSBORDER > size.y)
252 size.y = sizeText.y + 2 * TEXTFOCUSBORDER;
489468fe
SC
253
254 size.x = m_choice->GetPopupWidth() + sizeText.x + MARGIN;
255 size.x += TEXTFOCUSBORDER ;
489468fe
SC
256 }
257 else
258 {
259 // clipping is too tight
260 size.y += 1 ;
261 }
262
263 return size;
264}
265
266void wxComboBox::DoMoveWindow(int x, int y, int width, int height)
267{
268 wxControl::DoMoveWindow( x, y, width , height );
269
270 if ( m_text == NULL )
271 {
272 // we might not be fully constructed yet, therefore watch out...
273 if ( m_choice )
274 m_choice->SetSize(0, 0 , width, -1);
275 }
276 else
277 {
278 wxCoord wText = width - m_choice->GetPopupWidth() - MARGIN;
279 m_text->SetSize(TEXTFOCUSBORDER, TEXTFOCUSBORDER, wText, -1);
d33e45f1
SC
280 wxSize tSize = m_text->GetSize();
281 wxSize cSize = m_choice->GetSize();
03647350 282
d33e45f1 283 int yOffset = ( tSize.y + 2 * TEXTFOCUSBORDER - cSize.y ) / 2;
489468fe
SC
284
285 // put it at an inset of 1 to have outer area shadows drawn as well
d33e45f1 286 m_choice->SetSize(TEXTFOCUSBORDER + wText + MARGIN - 1 , yOffset, m_choice->GetPopupWidth() , -1);
489468fe
SC
287 }
288}
289
290// ----------------------------------------------------------------------------
291// operations forwarded to the subcontrols
292// ----------------------------------------------------------------------------
293
294bool wxComboBox::Enable(bool enable)
295{
296 if ( !wxControl::Enable(enable) )
297 return false;
298
299 if (m_text)
300 m_text->Enable(enable);
301
302 return true;
303}
304
305bool wxComboBox::Show(bool show)
306{
307 if ( !wxControl::Show(show) )
308 return false;
309
310 return true;
311}
312
313void wxComboBox::DelegateTextChanged( const wxString& value )
314{
315 SetStringSelection( value );
316}
317
318void wxComboBox::DelegateChoice( const wxString& value )
319{
320 SetStringSelection( value );
321}
322
323void wxComboBox::Init()
324{
325 WX_INIT_CONTROL_CONTAINER();
326}
327
328bool wxComboBox::Create(wxWindow *parent,
329 wxWindowID id,
330 const wxString& value,
331 const wxPoint& pos,
332 const wxSize& size,
333 const wxArrayString& choices,
334 long style,
335 const wxValidator& validator,
336 const wxString& name)
337{
338 if ( !Create( parent, id, value, pos, size, 0, NULL,
339 style, validator, name ) )
340 return false;
341
342 Append(choices);
343
344 return true;
345}
346
347bool wxComboBox::Create(wxWindow *parent,
348 wxWindowID id,
349 const wxString& value,
350 const wxPoint& pos,
351 const wxSize& size,
352 int n,
353 const wxString choices[],
354 long style,
355 const wxValidator& validator,
356 const wxString& name)
357{
358 if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style ,
359 validator, name) )
360 {
361 return false;
362 }
363
364 wxSize csize = size;
365 if ( style & wxCB_READONLY )
366 {
367 m_text = NULL;
368 }
369 else
370 {
371 m_text = new wxComboBoxText(this);
372 if ( size.y == -1 )
373 {
374 csize.y = m_text->GetSize().y ;
375 csize.y += 2 * TEXTFOCUSBORDER ;
376 }
377 }
378 m_choice = new wxComboBoxChoice(this, style );
379
380 DoSetSize(pos.x, pos.y, csize.x, csize.y);
381
382 Append( n, choices );
383
384 // Needed because it is a wxControlWithItems
385 SetInitialSize(size);
386 SetStringSelection(value);
387
388 return true;
389}
390
d9d551f6 391void wxComboBox::EnableTextChangedEvents(bool enable)
03647350 392{
d9d551f6
SC
393 if ( m_text )
394 m_text->ForwardEnableTextChangedEvents(enable);
395}
396
00c89b22
VZ
397wxString wxComboBox::DoGetValue() const
398{
399 wxCHECK_MSG( m_text, wxString(), "can't be called for read-only combobox" );
400
401 return m_text->GetValue();
402}
403
489468fe
SC
404wxString wxComboBox::GetValue() const
405{
406 wxString result;
407
408 if ( m_text == NULL )
409 result = m_choice->GetString( m_choice->GetSelection() );
410 else
411 result = m_text->GetValue();
412
413 return result;
414}
415
416unsigned int wxComboBox::GetCount() const
417{
418 return m_choice->GetCount() ;
419}
420
421void wxComboBox::SetValue(const wxString& value)
422{
423 if ( HasFlag(wxCB_READONLY) )
424 SetStringSelection( value ) ;
425 else
426 m_text->SetValue( value );
427}
428
429void wxComboBox::WriteText(const wxString& text)
430{
431 m_text->WriteText(text);
432}
433
434void wxComboBox::GetSelection(long *from, long *to) const
435{
436 m_text->GetSelection(from, to);
437}
438
439// Clipboard operations
440
441void wxComboBox::Copy()
442{
443 if ( m_text != NULL )
444 m_text->Copy();
445}
446
447void wxComboBox::Cut()
448{
449 if ( m_text != NULL )
450 m_text->Cut();
451}
452
453void wxComboBox::Paste()
454{
455 if ( m_text != NULL )
456 m_text->Paste();
457}
458
459void wxComboBox::SetEditable(bool editable)
460{
461 if ( ( m_text == NULL ) && editable )
462 {
463 m_text = new wxComboBoxText( this );
464 }
5276b0a5 465 else if ( !editable )
489468fe 466 {
5276b0a5 467 wxDELETE(m_text);
489468fe
SC
468 }
469
470 int currentX, currentY;
471 GetPosition( &currentX, &currentY );
472
473 int currentW, currentH;
474 GetSize( &currentW, &currentH );
475
476 DoMoveWindow( currentX, currentY, currentW, currentH );
477}
478
479void wxComboBox::SetInsertionPoint(long pos)
480{
481 if ( m_text )
482 m_text->SetInsertionPoint(pos);
483}
484
485void wxComboBox::SetInsertionPointEnd()
486{
487 if ( m_text )
488 m_text->SetInsertionPointEnd();
489}
490
491long wxComboBox::GetInsertionPoint() const
492{
493 if ( m_text )
494 return m_text->GetInsertionPoint();
495 return 0;
496}
497
498wxTextPos wxComboBox::GetLastPosition() const
499{
500 if ( m_text )
501 return m_text->GetLastPosition();
502 return 0;
503}
504
505void wxComboBox::Replace(long from, long to, const wxString& value)
506{
507 if ( m_text )
508 m_text->Replace(from,to,value);
509}
510
511void wxComboBox::Remove(long from, long to)
512{
513 if ( m_text )
514 m_text->Remove(from,to);
515}
516
517void wxComboBox::SetSelection(long from, long to)
518{
519 if ( m_text )
520 m_text->SetSelection(from,to);
521}
522
523int wxComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
524 unsigned int pos,
525 void **clientData,
526 wxClientDataType type)
527{
528 return m_choice->DoInsertItems(items, pos, clientData, type);
529}
530
531void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
532{
533 return m_choice->DoSetItemClientData( n , clientData ) ;
534}
535
536void* wxComboBox::DoGetItemClientData(unsigned int n) const
537{
538 return m_choice->DoGetItemClientData( n ) ;
539}
540
541wxClientDataType wxComboBox::GetClientDataType() const
542{
543 return m_choice->GetClientDataType();
544}
545
546void wxComboBox::SetClientDataType(wxClientDataType clientDataItemsType)
547{
548 m_choice->SetClientDataType(clientDataItemsType);
549}
550
551void wxComboBox::DoDeleteOneItem(unsigned int n)
552{
553 m_choice->DoDeleteOneItem( n );
554}
555
556void wxComboBox::DoClear()
557{
558 m_choice->DoClear();
559}
560
561int wxComboBox::GetSelection() const
562{
563 return m_choice->GetSelection();
564}
565
566void wxComboBox::SetSelection(int n)
567{
568 m_choice->SetSelection( n );
569
570 if ( m_text != NULL )
571 m_text->SetValue(n != wxNOT_FOUND ? GetString(n) : wxString(wxEmptyString));
572}
573
574int wxComboBox::FindString(const wxString& s, bool bCase) const
575{
576 return m_choice->FindString( s, bCase );
577}
578
579wxString wxComboBox::GetString(unsigned int n) const
580{
581 return m_choice->GetString( n );
582}
583
584wxString wxComboBox::GetStringSelection() const
585{
586 int sel = GetSelection();
587 if (sel != wxNOT_FOUND)
588 return wxString(this->GetString((unsigned int)sel));
589 else
590 return wxEmptyString;
591}
592
593void wxComboBox::SetString(unsigned int n, const wxString& s)
594{
595 m_choice->SetString( n , s );
596}
597
598bool wxComboBox::IsEditable() const
599{
600 return m_text != NULL && !HasFlag(wxCB_READONLY);
601}
602
603void wxComboBox::Undo()
604{
605 if (m_text != NULL)
606 m_text->Undo();
607}
608
609void wxComboBox::Redo()
610{
611 if (m_text != NULL)
612 m_text->Redo();
613}
614
615void wxComboBox::SelectAll()
616{
617 if (m_text != NULL)
618 m_text->SelectAll();
619}
620
621bool wxComboBox::CanCopy() const
622{
623 if (m_text != NULL)
624 return m_text->CanCopy();
625 else
626 return false;
627}
628
629bool wxComboBox::CanCut() const
630{
631 if (m_text != NULL)
632 return m_text->CanCut();
633 else
634 return false;
635}
636
637bool wxComboBox::CanPaste() const
638{
639 if (m_text != NULL)
640 return m_text->CanPaste();
641 else
642 return false;
643}
644
645bool wxComboBox::CanUndo() const
646{
647 if (m_text != NULL)
648 return m_text->CanUndo();
649 else
650 return false;
651}
652
653bool wxComboBox::CanRedo() const
654{
655 if (m_text != NULL)
656 return m_text->CanRedo();
657 else
658 return false;
659}
660
de0d2095 661bool wxComboBox::OSXHandleClicked( double WXUNUSED(timestampsec) )
489468fe
SC
662{
663/*
664 For consistency with other platforms, clicking in the text area does not constitute a selection
665 wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, m_windowId );
666 event.SetInt(GetSelection());
667 event.SetEventObject(this);
668 event.SetString(GetStringSelection());
669 ProcessCommand(event);
670*/
671
524c47aa 672 return true ;
489468fe
SC
673}
674
c84030e0
KO
675wxTextWidgetImpl* wxComboBox::GetTextPeer() const
676{
677 if (m_text)
678 return m_text->GetTextPeer();
ce00f59b 679
c84030e0
KO
680 return NULL;
681}
682
683#endif // wxUSE_COMBOBOX && wxOSX_USE_CARBON