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