]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/combobxc.cpp
avoid setting initial position if it was not specified, broken in r70734
[wxWidgets.git] / src / osx / carbon / combobxc.cpp
CommitLineData
489468fe 1/////////////////////////////////////////////////////////////////////////////
524c47aa 2// Name: src/osx/carbon/combobxc.cpp
489468fe
SC
3// Purpose: wxComboBox class using HIView ComboBox
4// Author: Stefan Csomor
5// Modified by:
6// Created: 1998-01-01
489468fe
SC
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
1f0c8f31 20#include "wx/osx/uma.h"
489468fe
SC
21#if TARGET_API_MAC_OSX
22#ifndef __HIVIEW__
23 #include <HIToolbox/HIView.h>
24#endif
25#endif
26
489468fe
SC
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
33static int nextPopUpMenuId = 1000;
34MenuHandle NewUniqueMenu()
35{
36 MenuHandle handle = NewMenu( nextPopUpMenuId , "\pMenu" );
37 nextPopUpMenuId++;
38 return handle;
39}
40
41#if USE_HICOMBOBOX
42static const EventTypeSpec eventList[] =
43{
44 { kEventClassTextField , kEventTextAccepted } ,
45};
46
47static 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 {
ce7fe42e 61 wxCommandEvent event( wxEVT_COMBOBOX, cb->GetId() );
489468fe
SC
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
80DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacComboBoxEventHandler )
81
82#endif
83
84// ----------------------------------------------------------------------------
85// constants
86// ----------------------------------------------------------------------------
87
88// the margin between the text control and the choice
89static const wxCoord MARGIN = 2;
90#if TARGET_API_MAC_OSX
91static const int POPUPWIDTH = 24;
92#else
93static const int POPUPWIDTH = 18;
94#endif
95static const int POPUPHEIGHT = 23;
96
97// ----------------------------------------------------------------------------
98// wxComboBoxText: text control forwards events to combobox
99// ----------------------------------------------------------------------------
100
101class wxComboBoxText : public wxTextCtrl
102{
103public:
104 wxComboBoxText( wxComboBox * cb )
105 : wxTextCtrl( cb , 1 )
106 {
107 m_cb = cb;
108 }
109
110protected:
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!
ce7fe42e 122 wxCommandEvent event( wxEVT_COMBOBOX, m_cb->GetId() );
489468fe
SC
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
ce7fe42e 137 wxCommandEvent event( wxEVT_COMBOBOX, m_cb->GetId() );
489468fe
SC
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 {
ce7fe42e 153 wxCommandEvent event(wxEVT_BUTTON, def->GetId() );
489468fe
SC
154 event.SetEventObject(def);
155 def->Command(event);
156 return;
157 }
158 }
159
160 return;
161 }
162 }
163
164 event.Skip();
165 }
166private:
167 wxComboBox *m_cb;
168
169 DECLARE_EVENT_TABLE()
170};
171
172BEGIN_EVENT_TABLE(wxComboBoxText, wxTextCtrl)
173 EVT_CHAR( wxComboBoxText::OnChar)
174END_EVENT_TABLE()
175
176class wxComboBoxChoice : public wxChoice
177{
178public:
179 wxComboBoxChoice(wxComboBox *cb, int style)
180 : wxChoice( cb , 1 )
181 {
182 m_cb = cb;
183 }
184
185protected:
186 void OnChoice( wxCommandEvent& e )
187 {
188 wxString s = e.GetString();
189
190 m_cb->DelegateChoice( s );
ce7fe42e 191 wxCommandEvent event2(wxEVT_COMBOBOX, m_cb->GetId() );
489468fe
SC
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
204private:
205 wxComboBox *m_cb;
206
207 DECLARE_EVENT_TABLE()
208};
209
210BEGIN_EVENT_TABLE(wxComboBoxChoice, wxChoice)
211 EVT_CHOICE(wxID_ANY, wxComboBoxChoice::OnChoice)
212END_EVENT_TABLE()
213
214wxComboBox::~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
524c47aa
SC
219 wxDELETE( m_text );
220 wxDELETE( m_choice );
489468fe
SC
221}
222
223
224// ----------------------------------------------------------------------------
225// geometry
226// ----------------------------------------------------------------------------
227
228wxSize 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
246void 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
275bool wxComboBox::Enable(bool enable)
276{
277 if ( !wxControl::Enable(enable) )
278 return false;
279
280 return true;
281}
282
283bool wxComboBox::Show(bool show)
284{
285 if ( !wxControl::Show(show) )
286 return false;
287
288 return true;
289}
290
291void 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
303void wxComboBox::DelegateTextChanged( const wxString& value )
304{
305 SetStringSelection( value );
306}
307
308
309void wxComboBox::DelegateChoice( const wxString& value )
310{
311 SetStringSelection( value );
312}
313
314
315bool 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
331bool 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
d15694e8 343 DontCreatePeer();
489468fe
SC
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
411wxString 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
433void 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
448void wxComboBox::Copy()
449{
450 if ( m_text != NULL )
451 {
452 m_text->Copy();
453 }
454}
455
456void wxComboBox::Cut()
457{
458 if ( m_text != NULL )
459 {
460 m_text->Cut();
461 }
462}
463
464void wxComboBox::Paste()
465{
466 if ( m_text != NULL )
467 {
468 m_text->Paste();
469 }
470}
471
472void wxComboBox::SetEditable(bool editable)
473{
474 if ( ( m_text == NULL ) && editable )
475 {
476 m_text = new wxComboBoxText( this );
477 }
5276b0a5 478 else if ( !editable )
489468fe 479 {
5276b0a5 480 wxDELETE(m_text);
489468fe
SC
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
492void wxComboBox::SetInsertionPoint(long pos)
493{
494 // TODO
495}
496
497void wxComboBox::SetInsertionPointEnd()
498{
499 // TODO
500}
501
502long wxComboBox::GetInsertionPoint() const
503{
504 // TODO
505 return 0;
506}
507
508wxTextPos wxComboBox::GetLastPosition() const
509{
510 // TODO
511 return 0;
512}
513
514void wxComboBox::Replace(long from, long to, const wxString& value)
515{
516 // TODO
517}
518
519void wxComboBox::Remove(long from, long to)
520{
521 // TODO
522}
523
524void wxComboBox::SetSelection(long from, long to)
525{
526 // TODO
527}
528
529int 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
552void 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
561void* 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
570unsigned 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
578void 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
587void 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
598int wxComboBox::GetSelection() const
599{
600#if USE_HICOMBOBOX
601 return FindString( GetStringSelection() );
602#else
603 return m_choice->GetSelection();
604#endif
605}
606
607void 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
621int 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
635wxString 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
646wxString 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
659void 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
670bool 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
680void wxComboBox::Undo()
681{
682#if USE_HICOMBOBOX
683 // TODO
684#else
685 if (m_text != NULL)
686 m_text->Undo();
687#endif
688}
689
690void wxComboBox::Redo()
691{
692#if USE_HICOMBOBOX
693 // TODO
694#else
695 if (m_text != NULL)
696 m_text->Redo();
697#endif
698}
699
700void wxComboBox::SelectAll()
701{
702#if USE_HICOMBOBOX
703 // TODO
704#else
705 if (m_text != NULL)
706 m_text->SelectAll();
707#endif
708}
709
710bool 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
723bool 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
736bool 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
749bool 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
762bool 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
4eb5a0ec 775bool wxComboBox::OSXHandleClicked( double timestampsec )
489468fe 776{
ce7fe42e 777 wxCommandEvent event(wxEVT_COMBOBOX, m_windowId );
489468fe
SC
778 event.SetInt(GetSelection());
779 event.SetEventObject(this);
780 event.SetString(GetStringSelection());
781 ProcessCommand(event);
524c47aa 782 return true;
489468fe 783}