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