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