]> git.saurik.com Git - wxWidgets.git/blob - src/osx/carbon/combobxc.cpp
guarding open combo box against AppDefined NSEvents issued by wxEventLoop::WakeUp...
[wxWidgets.git] / src / osx / carbon / combobxc.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/combobxc.cpp
3 // Purpose: wxComboBox class using HIView ComboBox
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 #include "wx/combobox.h"
15
16 #ifndef WX_PRECOMP
17 #include "wx/button.h"
18 #include "wx/menu.h"
19 #endif
20
21 #include "wx/osx/uma.h"
22 #if TARGET_API_MAC_OSX
23 #ifndef __HIVIEW__
24 #include <HIToolbox/HIView.h>
25 #endif
26 #endif
27
28 #if TARGET_API_MAC_OSX
29 #define USE_HICOMBOBOX 1 //use hi combobox define
30 #else
31 #define USE_HICOMBOBOX 0
32 #endif
33
34 static int nextPopUpMenuId = 1000;
35 MenuHandle NewUniqueMenu()
36 {
37 MenuHandle handle = NewMenu( nextPopUpMenuId , "\pMenu" );
38 nextPopUpMenuId++;
39 return handle;
40 }
41
42 #if USE_HICOMBOBOX
43 static const EventTypeSpec eventList[] =
44 {
45 { kEventClassTextField , kEventTextAccepted } ,
46 };
47
48 static pascal OSStatus wxMacComboBoxEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
49 {
50 OSStatus result = eventNotHandledErr;
51 wxComboBox* cb = (wxComboBox*) data;
52
53 wxMacCarbonEvent cEvent( event );
54
55 switch( cEvent.GetClass() )
56 {
57 case kEventClassTextField :
58 switch( cEvent.GetKind() )
59 {
60 case kEventTextAccepted :
61 {
62 wxCommandEvent event( wxEVT_COMBOBOX, cb->GetId() );
63 event.SetInt( cb->GetSelection() );
64 event.SetString( cb->GetStringSelection() );
65 event.SetEventObject( cb );
66 cb->HandleWindowEvent( event );
67 }
68 break;
69 default :
70 break;
71 }
72 break;
73 default :
74 break;
75 }
76
77
78 return result;
79 }
80
81 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacComboBoxEventHandler )
82
83 #endif
84
85 // ----------------------------------------------------------------------------
86 // constants
87 // ----------------------------------------------------------------------------
88
89 // the margin between the text control and the choice
90 static const wxCoord MARGIN = 2;
91 #if TARGET_API_MAC_OSX
92 static const int POPUPWIDTH = 24;
93 #else
94 static const int POPUPWIDTH = 18;
95 #endif
96 static const int POPUPHEIGHT = 23;
97
98 // ----------------------------------------------------------------------------
99 // wxComboBoxText: text control forwards events to combobox
100 // ----------------------------------------------------------------------------
101
102 class wxComboBoxText : public wxTextCtrl
103 {
104 public:
105 wxComboBoxText( wxComboBox * cb )
106 : wxTextCtrl( cb , 1 )
107 {
108 m_cb = cb;
109 }
110
111 protected:
112 void OnChar( wxKeyEvent& event )
113 {
114 if ( event.GetKeyCode() == WXK_RETURN )
115 {
116 wxString value = GetValue();
117
118 if ( m_cb->GetCount() == 0 )
119 {
120 // make Enter generate "selected" event if there is only one item
121 // in the combobox - without it, it's impossible to select it at
122 // all!
123 wxCommandEvent event( wxEVT_COMBOBOX, m_cb->GetId() );
124 event.SetInt( 0 );
125 event.SetString( value );
126 event.SetEventObject( m_cb );
127 m_cb->HandleWindowEvent( event );
128 }
129 else
130 {
131 // add the item to the list if it's not there yet
132 if ( m_cb->FindString(value) == wxNOT_FOUND )
133 {
134 m_cb->Append(value);
135 m_cb->SetStringSelection(value);
136
137 // and generate the selected event for it
138 wxCommandEvent event( wxEVT_COMBOBOX, m_cb->GetId() );
139 event.SetInt( m_cb->GetCount() - 1 );
140 event.SetString( value );
141 event.SetEventObject( m_cb );
142 m_cb->HandleWindowEvent( event );
143 }
144
145 // This will invoke the dialog default action, such
146 // as the clicking the default button.
147
148 wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
149 if ( tlw && tlw->GetDefaultItem() )
150 {
151 wxButton *def = wxDynamicCast(tlw->GetDefaultItem(), wxButton);
152 if ( def && def->IsEnabled() )
153 {
154 wxCommandEvent event(wxEVT_BUTTON, def->GetId() );
155 event.SetEventObject(def);
156 def->Command(event);
157 return;
158 }
159 }
160
161 return;
162 }
163 }
164
165 event.Skip();
166 }
167 private:
168 wxComboBox *m_cb;
169
170 DECLARE_EVENT_TABLE()
171 };
172
173 BEGIN_EVENT_TABLE(wxComboBoxText, wxTextCtrl)
174 EVT_CHAR( wxComboBoxText::OnChar)
175 END_EVENT_TABLE()
176
177 class wxComboBoxChoice : public wxChoice
178 {
179 public:
180 wxComboBoxChoice(wxComboBox *cb, int style)
181 : wxChoice( cb , 1 )
182 {
183 m_cb = cb;
184 }
185
186 protected:
187 void OnChoice( wxCommandEvent& e )
188 {
189 wxString s = e.GetString();
190
191 m_cb->DelegateChoice( s );
192 wxCommandEvent event2(wxEVT_COMBOBOX, m_cb->GetId() );
193 event2.SetInt(m_cb->GetSelection());
194 event2.SetEventObject(m_cb);
195 event2.SetString(m_cb->GetStringSelection());
196 m_cb->ProcessCommand(event2);
197 }
198 virtual wxSize DoGetBestSize() const
199 {
200 wxSize sz = wxChoice::DoGetBestSize();
201 sz.x = POPUPWIDTH;
202 return sz;
203 }
204
205 private:
206 wxComboBox *m_cb;
207
208 DECLARE_EVENT_TABLE()
209 };
210
211 BEGIN_EVENT_TABLE(wxComboBoxChoice, wxChoice)
212 EVT_CHOICE(wxID_ANY, wxComboBoxChoice::OnChoice)
213 END_EVENT_TABLE()
214
215 wxComboBox::~wxComboBox()
216 {
217 // delete the controls now, don't leave them alive even though they would
218 // still be eventually deleted by our parent - but it will be too late, the
219 // user code expects them to be gone now
220 wxDELETE( m_text );
221 wxDELETE( m_choice );
222 }
223
224
225 // ----------------------------------------------------------------------------
226 // geometry
227 // ----------------------------------------------------------------------------
228
229 wxSize wxComboBox::DoGetBestSize() const
230 {
231 #if USE_HICOMBOBOX
232 return wxControl::DoGetBestSize();
233 #else
234 wxSize size = m_choice->GetBestSize();
235
236 if ( m_text != NULL )
237 {
238 wxSize sizeText = m_text->GetBestSize();
239
240 size.x = POPUPWIDTH + sizeText.x + MARGIN;
241 }
242
243 return size;
244 #endif
245 }
246
247 void wxComboBox::DoMoveWindow(int x, int y, int width, int height) {
248 #if USE_HICOMBOBOX
249 wxControl::DoMoveWindow(x, y, width, height);
250 #else
251 height = POPUPHEIGHT;
252
253 wxControl::DoMoveWindow(x, y, width, height);
254
255 if ( m_text == NULL )
256 {
257 // we might not be fully constructed yet, therefore watch out...
258 if ( m_choice )
259 m_choice->SetSize(0, 0 , width, wxDefaultCoord);
260 }
261 else
262 {
263 wxCoord wText = width - POPUPWIDTH - MARGIN;
264 m_text->SetSize(0, 0, wText, height);
265 m_choice->SetSize(0 + wText + MARGIN, 0, POPUPWIDTH, wxDefaultCoord);
266 }
267 #endif
268 }
269
270
271
272 // ----------------------------------------------------------------------------
273 // operations forwarded to the subcontrols
274 // ----------------------------------------------------------------------------
275
276 bool wxComboBox::Enable(bool enable)
277 {
278 if ( !wxControl::Enable(enable) )
279 return false;
280
281 return true;
282 }
283
284 bool wxComboBox::Show(bool show)
285 {
286 if ( !wxControl::Show(show) )
287 return false;
288
289 return true;
290 }
291
292 void wxComboBox::SetFocus()
293 {
294 #if USE_HICOMBOBOX
295 wxControl::SetFocus();
296 #else
297 if ( m_text != NULL) {
298 m_text->SetFocus();
299 }
300 #endif
301 }
302
303
304 void wxComboBox::DelegateTextChanged( const wxString& value )
305 {
306 SetStringSelection( value );
307 }
308
309
310 void wxComboBox::DelegateChoice( const wxString& value )
311 {
312 SetStringSelection( value );
313 }
314
315
316 bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
317 const wxString& value,
318 const wxPoint& pos,
319 const wxSize& size,
320 const wxArrayString& choices,
321 long style,
322 const wxValidator& validator,
323 const wxString& name)
324 {
325 wxCArrayString chs( choices );
326
327 return Create( parent, id, value, pos, size, chs.GetCount(),
328 chs.GetStrings(), style, validator, name );
329 }
330
331
332 bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
333 const wxString& value,
334 const wxPoint& pos,
335 const wxSize& size,
336 int n, const wxString choices[],
337 long style,
338 const wxValidator& validator,
339 const wxString& name)
340 {
341 m_text = NULL;
342 m_choice = NULL;
343 #if USE_HICOMBOBOX
344 DontCreatePeer();
345 #endif
346 if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style ,
347 wxDefaultValidator, name) )
348 {
349 return false;
350 }
351 #if USE_HICOMBOBOX
352 Rect bounds = wxMacGetBoundsForControl( this , pos , size );
353 HIRect hiRect;
354
355 hiRect.origin.x = 20; //bounds.left;
356 hiRect.origin.y = 25; //bounds.top;
357 hiRect.size.width = 120;// bounds.right - bounds.left;
358 hiRect.size.height = 24;
359
360 //For some reason, this code causes the combo box not to be displayed at all.
361 //hiRect.origin.x = bounds.left;
362 //hiRect.origin.y = bounds.top;
363 //hiRect.size.width = bounds.right - bounds.left;
364 //hiRect.size.height = bounds.bottom - bounds.top;
365 //printf("left = %d, right = %d, top = %d, bottom = %d\n", bounds.left, bounds.right, bounds.top, bounds.bottom);
366 //printf("x = %d, y = %d, width = %d, height = %d\n", hibounds.origin.x, hibounds.origin.y, hibounds.size.width, hibounds.size.height);
367 m_peer = new wxMacControl(this);
368 verify_noerr( HIComboBoxCreate( &hiRect, CFSTR(""), NULL, NULL, kHIComboBoxStandardAttributes, m_peer->GetControlRefAddr() ) );
369
370
371 m_peer->SetMinimum( 0 );
372 m_peer->SetMaximum( 100);
373 if ( n > 0 )
374 m_peer->SetValue( 1 );
375
376 MacPostControlCreate(pos,size);
377
378 Append( choices[ i ] );
379
380 HIViewSetVisible( m_peer->GetControlRef(), true );
381 SetSelection(0);
382 EventHandlerRef comboEventHandler;
383 InstallControlEventHandler( m_peer->GetControlRef(), GetwxMacComboBoxEventHandlerUPP(),
384 GetEventTypeCount(eventList), eventList, this,
385 (EventHandlerRef *)&comboEventHandler);
386 #else
387 m_choice = new wxComboBoxChoice(this, style );
388 m_choice->SetMinSize( wxSize( POPUPWIDTH , POPUPHEIGHT ) );
389
390 wxSize csize = size;
391 if ( style & wxCB_READONLY )
392 {
393 m_text = NULL;
394 }
395 else
396 {
397 m_text = new wxComboBoxText(this);
398 if ( size.y == wxDefaultCoord ) {
399 csize.y = m_text->GetSize().y;
400 }
401 }
402
403 DoSetSize(pos.x, pos.y, csize.x, csize.y);
404
405 m_choice->Append( n, choices );
406 SetInitialSize(csize); // Needed because it is a wxControlWithItems
407 #endif
408
409 return true;
410 }
411
412 wxString wxComboBox::GetValue() const
413 {
414 #if USE_HICOMBOBOX
415 CFStringRef myString;
416 HIComboBoxCopyTextItemAtIndex( m_peer->GetControlRef(), (CFIndex)GetSelection(), &myString );
417 return wxMacCFStringHolder( myString, GetFont().GetEncoding() ).AsString();
418 #else
419 wxString result;
420
421 if ( m_text == NULL )
422 {
423 result = m_choice->GetString( m_choice->GetSelection() );
424 }
425 else
426 {
427 result = m_text->GetValue();
428 }
429
430 return result;
431 #endif
432 }
433
434 void wxComboBox::SetValue(const wxString& value)
435 {
436 #if USE_HICOMBOBOX
437
438 #else
439 int s = FindString (value);
440 if (s == wxNOT_FOUND && !HasFlag(wxCB_READONLY) )
441 {
442 m_choice->Append(value);
443 }
444 SetStringSelection( value );
445 #endif
446 }
447
448 // Clipboard operations
449 void wxComboBox::Copy()
450 {
451 if ( m_text != NULL )
452 {
453 m_text->Copy();
454 }
455 }
456
457 void wxComboBox::Cut()
458 {
459 if ( m_text != NULL )
460 {
461 m_text->Cut();
462 }
463 }
464
465 void wxComboBox::Paste()
466 {
467 if ( m_text != NULL )
468 {
469 m_text->Paste();
470 }
471 }
472
473 void wxComboBox::SetEditable(bool editable)
474 {
475 if ( ( m_text == NULL ) && editable )
476 {
477 m_text = new wxComboBoxText( this );
478 }
479 else if ( !editable )
480 {
481 wxDELETE(m_text);
482 }
483
484 int currentX, currentY;
485 GetPosition( &currentX, &currentY );
486
487 int currentW, currentH;
488 GetSize( &currentW, &currentH );
489
490 DoMoveWindow( currentX, currentY, currentW, currentH );
491 }
492
493 void wxComboBox::SetInsertionPoint(long pos)
494 {
495 // TODO
496 }
497
498 void wxComboBox::SetInsertionPointEnd()
499 {
500 // TODO
501 }
502
503 long wxComboBox::GetInsertionPoint() const
504 {
505 // TODO
506 return 0;
507 }
508
509 wxTextPos wxComboBox::GetLastPosition() const
510 {
511 // TODO
512 return 0;
513 }
514
515 void wxComboBox::Replace(long from, long to, const wxString& value)
516 {
517 // TODO
518 }
519
520 void wxComboBox::Remove(long from, long to)
521 {
522 // TODO
523 }
524
525 void wxComboBox::SetSelection(long from, long to)
526 {
527 // TODO
528 }
529
530 int wxComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
531 unsigned int pos,
532 void **clientData, wxClientDataType type)
533 {
534 #if USE_HICOMBOBOX
535 const unsigned int count = items.GetCount();
536 for ( unsigned int i = 0; i < count; ++i, ++pos )
537 {
538 HIComboBoxInsertTextItemAtIndex(m_peer->GetControlRef(),
539 (CFIndex)pos,
540 wxMacCFStringHolder(items[i],
541 GetFont().GetEncoding()));
542 AssignNewItemClientData(pos, clientData, i, type);
543 }
544
545 //SetControl32BitMaximum( m_peer->GetControlRef(), GetCount() );
546
547 return pos - 1;
548 #else
549 return m_choice->DoInsertItems( items, pos, clientData, type );
550 #endif
551 }
552
553 void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
554 {
555 #if USE_HICOMBOBOX
556 return; //TODO
557 #else
558 return m_choice->DoSetItemClientData( n , clientData );
559 #endif
560 }
561
562 void* wxComboBox::DoGetItemClientData(unsigned int n) const
563 {
564 #if USE_HICOMBOBOX
565 return NULL; //TODO
566 #else
567 return m_choice->DoGetItemClientData( n );
568 #endif
569 }
570
571 unsigned int wxComboBox::GetCount() const {
572 #if USE_HICOMBOBOX
573 return (unsigned int) HIComboBoxGetItemCount( m_peer->GetControlRef() );
574 #else
575 return m_choice->GetCount();
576 #endif
577 }
578
579 void wxComboBox::DoDeleteOneItem(unsigned int n)
580 {
581 #if USE_HICOMBOBOX
582 HIComboBoxRemoveItemAtIndex( m_peer->GetControlRef(), (CFIndex)n );
583 #else
584 m_choice->Delete( n );
585 #endif
586 }
587
588 void wxComboBox::DoClear()
589 {
590 #if USE_HICOMBOBOX
591 for ( CFIndex i = GetCount() - 1; i >= 0; ++ i )
592 verify_noerr( HIComboBoxRemoveItemAtIndex( m_peer->GetControlRef(), i ) );
593 m_peer->SetData<CFStringRef>(kHIComboBoxEditTextPart,kControlEditTextCFStringTag,CFSTR(""));
594 #else
595 m_choice->Clear();
596 #endif
597 }
598
599 int wxComboBox::GetSelection() const
600 {
601 #if USE_HICOMBOBOX
602 return FindString( GetStringSelection() );
603 #else
604 return m_choice->GetSelection();
605 #endif
606 }
607
608 void wxComboBox::SetSelection(int n)
609 {
610 #if USE_HICOMBOBOX
611 SetControl32BitValue( m_peer->GetControlRef() , n + 1 );
612 #else
613 m_choice->SetSelection( n );
614
615 if ( m_text != NULL )
616 {
617 m_text->SetValue(GetString(n));
618 }
619 #endif
620 }
621
622 int wxComboBox::FindString(const wxString& s, bool bCase) const
623 {
624 #if USE_HICOMBOBOX
625 for( unsigned int i = 0 ; i < GetCount() ; i++ )
626 {
627 if (GetString(i).IsSameAs(s, bCase) )
628 return i ;
629 }
630 return wxNOT_FOUND;
631 #else
632 return m_choice->FindString( s, bCase );
633 #endif
634 }
635
636 wxString wxComboBox::GetString(unsigned int n) const
637 {
638 #if USE_HICOMBOBOX
639 CFStringRef itemText;
640 HIComboBoxCopyTextItemAtIndex( m_peer->GetControlRef(), (CFIndex)n, &itemText );
641 return wxMacCFStringHolder(itemText).AsString();
642 #else
643 return m_choice->GetString( n );
644 #endif
645 }
646
647 wxString wxComboBox::GetStringSelection() const
648 {
649 #if USE_HICOMBOBOX
650 return wxMacCFStringHolder(m_peer->GetData<CFStringRef>(kHIComboBoxEditTextPart,kControlEditTextCFStringTag)).AsString();
651 #else
652 int sel = GetSelection ();
653 if (sel != wxNOT_FOUND)
654 return wxString(this->GetString((unsigned int)sel));
655 else
656 return wxEmptyString;
657 #endif
658 }
659
660 void wxComboBox::SetString(unsigned int n, const wxString& s)
661 {
662 #if USE_HICOMBOBOX
663 verify_noerr ( HIComboBoxInsertTextItemAtIndex( m_peer->GetControlRef(), (CFIndex) n,
664 wxMacCFStringHolder(s, GetFont().GetEncoding()) ) );
665 verify_noerr ( HIComboBoxRemoveItemAtIndex( m_peer->GetControlRef(), (CFIndex) n + 1 ) );
666 #else
667 m_choice->SetString( n , s );
668 #endif
669 }
670
671 bool wxComboBox::IsEditable() const
672 {
673 #if USE_HICOMBOBOX
674 // TODO
675 return !HasFlag(wxCB_READONLY);
676 #else
677 return m_text != NULL && !HasFlag(wxCB_READONLY);
678 #endif
679 }
680
681 void wxComboBox::Undo()
682 {
683 #if USE_HICOMBOBOX
684 // TODO
685 #else
686 if (m_text != NULL)
687 m_text->Undo();
688 #endif
689 }
690
691 void wxComboBox::Redo()
692 {
693 #if USE_HICOMBOBOX
694 // TODO
695 #else
696 if (m_text != NULL)
697 m_text->Redo();
698 #endif
699 }
700
701 void wxComboBox::SelectAll()
702 {
703 #if USE_HICOMBOBOX
704 // TODO
705 #else
706 if (m_text != NULL)
707 m_text->SelectAll();
708 #endif
709 }
710
711 bool wxComboBox::CanCopy() const
712 {
713 #if USE_HICOMBOBOX
714 // TODO
715 return false;
716 #else
717 if (m_text != NULL)
718 return m_text->CanCopy();
719 else
720 return false;
721 #endif
722 }
723
724 bool wxComboBox::CanCut() const
725 {
726 #if USE_HICOMBOBOX
727 // TODO
728 return false;
729 #else
730 if (m_text != NULL)
731 return m_text->CanCut();
732 else
733 return false;
734 #endif
735 }
736
737 bool wxComboBox::CanPaste() const
738 {
739 #if USE_HICOMBOBOX
740 // TODO
741 return false;
742 #else
743 if (m_text != NULL)
744 return m_text->CanPaste();
745 else
746 return false;
747 #endif
748 }
749
750 bool wxComboBox::CanUndo() const
751 {
752 #if USE_HICOMBOBOX
753 // TODO
754 return false;
755 #else
756 if (m_text != NULL)
757 return m_text->CanUndo();
758 else
759 return false;
760 #endif
761 }
762
763 bool wxComboBox::CanRedo() const
764 {
765 #if USE_HICOMBOBOX
766 // TODO
767 return false;
768 #else
769 if (m_text != NULL)
770 return m_text->CanRedo();
771 else
772 return false;
773 #endif
774 }
775
776 bool wxComboBox::OSXHandleClicked( double timestampsec )
777 {
778 wxCommandEvent event(wxEVT_COMBOBOX, m_windowId );
779 event.SetInt(GetSelection());
780 event.SetEventObject(this);
781 event.SetString(GetStringSelection());
782 ProcessCommand(event);
783 return true;
784 }