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