1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxComboBox class 
   4 // Author:      Stefan Csomor 
   8 // Copyright:   (c) Stefan Csomor 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  13 #pragma implementation "combobox.h" 
  16 #include "wx/wxprec.h" 
  18 #include "wx/combobox.h" 
  19 #include "wx/button.h" 
  21 #include "wx/mac/uma.h" 
  22 #if TARGET_API_MAC_OSX 
  24     #include <HIToolbox/HIView.h> 
  28 #if !USE_SHARED_LIBRARY 
  29 IMPLEMENT_DYNAMIC_CLASS(wxComboBox
, wxControl
) 
  32 // composite combobox implementation by Dan "Bud" Keith bud@otsys.com 
  34 #if TARGET_API_MAC_OSX 
  35 #define USE_HICOMBOBOX 1 //use hi combobox define 
  37 #define USE_HICOMBOBOX 0 
  40 static int nextPopUpMenuId 
= 1000 ; 
  41 MenuHandle 
NewUniqueMenu() 
  43   MenuHandle handle 
= NewMenu( nextPopUpMenuId 
, "\pMenu" ) ; 
  49 static const EventTypeSpec eventList
[] = 
  51     { kEventClassTextField 
, kEventTextAccepted 
} , 
  54 static pascal OSStatus 
wxMacComboBoxEventHandler( EventHandlerCallRef handler 
, EventRef event 
, void *data 
) 
  56     OSStatus result 
= eventNotHandledErr 
; 
  57     wxComboBox
* cb 
= (wxComboBox
*) data 
; 
  59     wxMacCarbonEvent 
cEvent( event 
) ; 
  61     switch( cEvent
.GetClass() ) 
  63         case kEventClassTextField 
: 
  64             switch( cEvent
.GetKind() ) 
  66                 case kEventTextAccepted 
: 
  68                         wxCommandEvent 
event( wxEVT_COMMAND_COMBOBOX_SELECTED
, cb
->GetId() ); 
  69                         event
.SetInt( cb
->GetSelection() ); 
  70                         event
.SetString( cb
->GetStringSelection() ); 
  71                         event
.SetEventObject( cb 
); 
  72                         cb
->GetEventHandler()->ProcessEvent( event 
); 
  87 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacComboBoxEventHandler 
) 
  91 // ---------------------------------------------------------------------------- 
  93 // ---------------------------------------------------------------------------- 
  95 // the margin between the text control and the choice 
  96 static const wxCoord MARGIN 
= 2; 
  97 #if TARGET_API_MAC_OSX 
  98 static const int    POPUPWIDTH 
= 24; 
 100 static const int    POPUPWIDTH 
= 18; 
 102 static const int    POPUPHEIGHT 
= 23; 
 104 // ---------------------------------------------------------------------------- 
 105 // wxComboBoxText: text control forwards events to combobox 
 106 // ---------------------------------------------------------------------------- 
 108 class wxComboBoxText 
: public wxTextCtrl
 
 111     wxComboBoxText( wxComboBox 
* cb 
) 
 112         : wxTextCtrl( cb 
, 1 ) 
 118     void OnChar( wxKeyEvent
& event 
) 
 120         if ( event
.GetKeyCode() == WXK_RETURN 
) 
 122             wxString value 
= GetValue(); 
 124             if ( m_cb
->GetCount() == 0 ) 
 126                 // make Enter generate "selected" event if there is only one item 
 127                 // in the combobox - without it, it's impossible to select it at 
 129                 wxCommandEvent 
event( wxEVT_COMMAND_COMBOBOX_SELECTED
, m_cb
->GetId() ); 
 131                 event
.SetString( value 
); 
 132                 event
.SetEventObject( m_cb 
); 
 133                 m_cb
->GetEventHandler()->ProcessEvent( event 
); 
 137                 // add the item to the list if it's not there yet 
 138                 if ( m_cb
->FindString(value
) == wxNOT_FOUND 
) 
 141                     m_cb
->SetStringSelection(value
); 
 143                     // and generate the selected event for it 
 144                     wxCommandEvent 
event( wxEVT_COMMAND_COMBOBOX_SELECTED
, m_cb
->GetId() ); 
 145                     event
.SetInt( m_cb
->GetCount() - 1 ); 
 146                     event
.SetString( value 
); 
 147                     event
.SetEventObject( m_cb 
); 
 148                     m_cb
->GetEventHandler()->ProcessEvent( event 
); 
 151                 // This will invoke the dialog default action, such 
 152                 // as the clicking the default button. 
 154                 wxWindow 
*parent 
= GetParent(); 
 155                 while( parent 
&& !parent
->IsTopLevel() && parent
->GetDefaultItem() == NULL 
) { 
 156                     parent 
= parent
->GetParent() ; 
 158                 if ( parent 
&& parent
->GetDefaultItem() ) 
 160                     wxButton 
*def 
= wxDynamicCast(parent
->GetDefaultItem(), 
 162                     if ( def 
&& def
->IsEnabled() ) 
 164                         wxCommandEvent 
event(wxEVT_COMMAND_BUTTON_CLICKED
, def
->GetId() ); 
 165                         event
.SetEventObject(def
); 
 180     DECLARE_EVENT_TABLE() 
 183 BEGIN_EVENT_TABLE(wxComboBoxText
, wxTextCtrl
) 
 184     EVT_CHAR( wxComboBoxText::OnChar
) 
 187 class wxComboBoxChoice 
: public wxChoice
 
 190     wxComboBoxChoice(wxComboBox 
*cb
, int style
) 
 197     void OnChoice( wxCommandEvent
& e 
) 
 199         wxString    s 
= e
.GetString(); 
 201         m_cb
->DelegateChoice( s 
); 
 202         wxCommandEvent 
event2(wxEVT_COMMAND_COMBOBOX_SELECTED
, m_cb
->GetId() ); 
 203         event2
.SetInt(m_cb
->GetSelection()); 
 204         event2
.SetEventObject(m_cb
); 
 205         event2
.SetString(m_cb
->GetStringSelection()); 
 206         m_cb
->ProcessCommand(event2
); 
 208     virtual wxSize 
DoGetBestSize() const 
 210         wxSize sz 
= wxChoice::DoGetBestSize() ; 
 218     DECLARE_EVENT_TABLE() 
 221 BEGIN_EVENT_TABLE(wxComboBoxChoice
, wxChoice
) 
 222     EVT_CHOICE(-1, wxComboBoxChoice::OnChoice
) 
 225 wxComboBox::~wxComboBox() 
 227     // delete client objects 
 230     // delete the controls now, don't leave them alive even though they would 
 231     // still be eventually deleted by our parent - but it will be too late, the 
 232     // user code expects them to be gone now 
 233     if (m_text 
!= NULL
) { 
 237     if (m_choice 
!= NULL
) { 
 244 // ---------------------------------------------------------------------------- 
 246 // ---------------------------------------------------------------------------- 
 248 wxSize 
wxComboBox::DoGetBestSize() const 
 251     return wxControl::DoGetBestSize(); 
 253     wxSize size 
= m_choice
->GetBestSize(); 
 255     if ( m_text 
!= NULL 
) 
 257         wxSize  sizeText 
= m_text
->GetBestSize(); 
 259         size
.x 
= POPUPWIDTH 
+ sizeText
.x 
+ MARGIN
; 
 266 void wxComboBox::DoMoveWindow(int x
, int y
, int width
, int height
) { 
 268     wxControl::DoMoveWindow(x
, y
, width
, height
); 
 270     height 
= POPUPHEIGHT
; 
 272     wxControl::DoMoveWindow(x
, y
, width
, height
); 
 274     if ( m_text 
== NULL 
) 
 276         // we might not be fully constructed yet, therefore watch out... 
 278             m_choice
->SetSize(0, 0 , width
, -1); 
 282         wxCoord wText 
= width 
- POPUPWIDTH 
- MARGIN
; 
 283         m_text
->SetSize(0, 0, wText
, height
); 
 284         m_choice
->SetSize(0 + wText 
+ MARGIN
, 0, POPUPWIDTH
, -1); 
 291 // ---------------------------------------------------------------------------- 
 292 // operations forwarded to the subcontrols 
 293 // ---------------------------------------------------------------------------- 
 295 bool wxComboBox::Enable(bool enable
) 
 297     if ( !wxControl::Enable(enable
) ) 
 303 bool wxComboBox::Show(bool show
) 
 305     if ( !wxControl::Show(show
) ) 
 311 void wxComboBox::SetFocus() 
 314     wxControl::SetFocus(); 
 316     if ( m_text 
!= NULL
) { 
 323 void wxComboBox::DelegateTextChanged( const wxString
& value 
) 
 325     SetStringSelection( value 
); 
 329 void wxComboBox::DelegateChoice( const wxString
& value 
) 
 331     SetStringSelection( value 
); 
 335 bool wxComboBox::Create(wxWindow 
*parent
, wxWindowID id
, 
 336            const wxString
& value
, 
 339            const wxArrayString
& choices
, 
 341            const wxValidator
& validator
, 
 342            const wxString
& name
) 
 344     wxCArrayString 
chs( choices 
); 
 346     return Create( parent
, id
, value
, pos
, size
, chs
.GetCount(), 
 347                    chs
.GetStrings(), style
, validator
, name 
); 
 351 bool wxComboBox::Create(wxWindow 
*parent
, wxWindowID id
, 
 352            const wxString
& value
, 
 355            int n
, const wxString choices
[], 
 357            const wxValidator
& validator
, 
 358            const wxString
& name
) 
 363     m_macIsUserPane 
= false ; 
 365     if ( !wxControl::Create(parent
, id
, wxDefaultPosition
, wxDefaultSize
, style 
, 
 366                             wxDefaultValidator
, name
) ) 
 371     Rect bounds 
= wxMacGetBoundsForControl( this , pos 
, size 
) ; 
 374     hiRect
.origin
.x 
= 20; //bounds.left; 
 375     hiRect
.origin
.y 
= 25; //bounds.top; 
 376     hiRect
.size
.width 
= 120;// bounds.right - bounds.left; 
 377     hiRect
.size
.height 
= 24; 
 379     //For some reason, this code causes the combo box not to be displayed at all. 
 380     //hiRect.origin.x = bounds.left; 
 381     //hiRect.origin.y = bounds.top; 
 382     //hiRect.size.width = bounds.right - bounds.left; 
 383     //hiRect.size.height = bounds.bottom - bounds.top; 
 384     //printf("left = %d, right = %d, top = %d, bottom = %d\n", bounds.left, bounds.right, bounds.top, bounds.bottom); 
 385     //printf("x = %d, y = %d, width = %d, height = %d\n", hibounds.origin.x, hibounds.origin.y, hibounds.size.width, hibounds.size.height); 
 386     m_peer 
= new wxMacControl(this) ; 
 387     verify_noerr( HIComboBoxCreate( &hiRect
, CFSTR(""), NULL
, NULL
, kHIComboBoxStandardAttributes
, *m_peer 
) ); 
 390     SetControl32BitMinimum( *m_peer 
, 0 ) ; 
 391     SetControl32BitMaximum( *m_peer 
, 100) ; 
 393         SetControl32BitValue( *m_peer 
, 1 ) ; 
 395     MacPostControlCreate(pos
,size
) ; 
 397     for ( int i 
= 0 ; i 
< n 
; i
++ ) 
 399         DoAppend( choices
[ i 
] ); 
 402     HIViewSetVisible( *m_peer
, true ); 
 404     EventHandlerRef comboEventHandler 
; 
 405     InstallControlEventHandler( *m_peer
, GetwxMacComboBoxEventHandlerUPP(), 
 406         GetEventTypeCount(eventList
), eventList
, this, 
 407         (EventHandlerRef 
*)&comboEventHandler
); 
 409     m_choice 
= new wxComboBoxChoice(this, style 
); 
 411     m_choice 
= new wxComboBoxChoice(this, style 
); 
 412     m_choice
->SetSizeHints( wxSize( POPUPWIDTH 
, POPUPHEIGHT 
) ) ; 
 415     if ( style 
& wxCB_READONLY 
) 
 421         m_text 
= new wxComboBoxText(this); 
 422         if ( size
.y 
== -1 ) { 
 423           csize
.y 
= m_text
->GetSize().y 
; 
 427     DoSetSize(pos
.x
, pos
.y
, csize
.x
, csize
.y
); 
 429     for ( int i 
= 0 ; i 
< n 
; i
++ ) 
 431         m_choice
->DoAppend( choices
[ i 
] ); 
 433     SetBestSize(csize
);   // Needed because it is a wxControlWithItems 
 439 wxString 
wxComboBox::GetValue() const 
 442     CFStringRef myString
; 
 443     HIComboBoxCopyTextItemAtIndex( *m_peer
, (CFIndex
)GetSelection(), &myString 
); 
 444     return wxMacCFStringHolder( myString
, m_font
.GetEncoding() ).AsString(); 
 448     if ( m_text 
== NULL 
) 
 450         result 
= m_choice
->GetString( m_choice
->GetSelection() ); 
 454         result 
= m_text
->GetValue(); 
 461 void wxComboBox::SetValue(const wxString
& value
) 
 466     int s 
= FindString (value
); 
 467     if (s 
== wxNOT_FOUND 
&& !HasFlag(wxCB_READONLY
) ) 
 469         m_choice
->Append(value
) ; 
 471     SetStringSelection( value 
) ; 
 475 // Clipboard operations 
 476 void wxComboBox::Copy() 
 478     if ( m_text 
!= NULL 
) 
 484 void wxComboBox::Cut() 
 486     if ( m_text 
!= NULL 
) 
 492 void wxComboBox::Paste() 
 494     if ( m_text 
!= NULL 
) 
 500 void wxComboBox::SetEditable(bool editable
) 
 502     if ( ( m_text 
== NULL 
) && editable 
) 
 504         m_text 
= new wxComboBoxText( this ); 
 506     else if ( ( m_text 
!= NULL 
) && !editable 
) 
 512     int currentX
, currentY
; 
 513     GetPosition( ¤tX
, ¤tY 
); 
 515     int currentW
, currentH
; 
 516     GetSize( ¤tW
, ¤tH 
); 
 518     DoMoveWindow( currentX
, currentY
, currentW
, currentH 
); 
 521 void wxComboBox::SetInsertionPoint(long pos
) 
 526 void wxComboBox::SetInsertionPointEnd() 
 531 long wxComboBox::GetInsertionPoint() const 
 537 wxTextPos 
wxComboBox::GetLastPosition() const 
 543 void wxComboBox::Replace(long from
, long to
, const wxString
& value
) 
 548 void wxComboBox::Remove(long from
, long to
) 
 553 void wxComboBox::SetSelection(long from
, long to
) 
 558 int wxComboBox::DoAppend(const wxString
& item
) 
 562     HIComboBoxAppendTextItem( *m_peer
, wxMacCFStringHolder( item
, m_font
.GetEncoding() ), &outIndex 
); 
 563     //SetControl32BitMaximum( *m_peer, GetCount() ); 
 564     return (int) outIndex
; 
 566     return m_choice
->DoAppend( item 
) ; 
 570 int wxComboBox::DoInsert(const wxString
& item
, int pos
) 
 573     HIComboBoxInsertTextItemAtIndex( *m_peer
, (CFIndex
)pos
, wxMacCFStringHolder(item
, m_font
.GetEncoding()) ); 
 575     //SetControl32BitMaximum( *m_peer, GetCount() ); 
 579     return m_choice
->DoInsert( item 
, pos 
) ; 
 583 void wxComboBox::DoSetItemClientData(int n
, void* clientData
) 
 588     return m_choice
->DoSetItemClientData( n 
, clientData 
) ; 
 592 void* wxComboBox::DoGetItemClientData(int n
) const 
 597     return m_choice
->DoGetItemClientData( n 
) ; 
 601 void wxComboBox::DoSetItemClientObject(int n
, wxClientData
* clientData
) 
 606     return m_choice
->DoSetItemClientObject( n 
, clientData 
) ; 
 610 wxClientData
* wxComboBox::DoGetItemClientObject(int n
) const 
 615     return m_choice
->DoGetItemClientObject( n 
) ; 
 619 void wxComboBox::FreeData() 
 621     if ( HasClientObjectData() ) 
 623         size_t count 
= GetCount(); 
 624         for ( size_t n 
= 0; n 
< count
; n
++ ) 
 626             SetClientObject( n
, NULL 
); 
 631 int wxComboBox::GetCount() const { 
 633     return (int) HIComboBoxGetItemCount( *m_peer 
); 
 635     return m_choice
->GetCount() ; 
 639 void wxComboBox::Delete(int n
) 
 642     HIComboBoxRemoveItemAtIndex( *m_peer
, (CFIndex
)n 
); 
 644     // force client object deletion 
 645     if( HasClientObjectData() ) 
 646         SetClientObject( n
, NULL 
); 
 647     m_choice
->Delete( n 
); 
 651 void wxComboBox::Clear() 
 655     for ( CFIndex i 
= GetCount() - 1 ; i 
>= 0 ; ++ i 
) 
 656         verify_noerr( HIComboBoxRemoveItemAtIndex( *m_peer
, i 
) ); 
 657     m_peer
->SetData
<CFStringRef
>(kHIComboBoxEditTextPart
,kControlEditTextCFStringTag
,CFSTR("")); 
 663 int wxComboBox::GetSelection() const 
 666     return FindString( GetStringSelection() ) ; 
 668     return m_choice
->GetSelection(); 
 672 void wxComboBox::SetSelection(int n
) 
 675     SetControl32BitValue( *m_peer 
, n 
+ 1 ) ; 
 677     m_choice
->SetSelection( n 
); 
 679     if ( m_text 
!= NULL 
) 
 681         m_text
->SetValue( GetString( n 
) ); 
 686 int wxComboBox::FindString(const wxString
& s
) const 
 689     for( int i 
= 0 ; i 
< GetCount() ; i
++ ) 
 691         if ( GetString( i 
).IsSameAs(s
, false) ) 
 696     return m_choice
->FindString( s 
); 
 700 wxString 
wxComboBox::GetString(int n
) const 
 703     CFStringRef itemText
; 
 704     HIComboBoxCopyTextItemAtIndex( *m_peer
, (CFIndex
)n
, &itemText 
); 
 705     return wxMacCFStringHolder(itemText
).AsString(); 
 707     return m_choice
->GetString( n 
); 
 711 wxString 
wxComboBox::GetStringSelection() const 
 714     return wxMacCFStringHolder(m_peer
->GetData
<CFStringRef
>(kHIComboBoxEditTextPart
,kControlEditTextCFStringTag
)).AsString() ; 
 716     int sel 
= GetSelection (); 
 718         return wxString(this->GetString (sel
)); 
 720         return wxEmptyString
; 
 724 void wxComboBox::SetString(int n
, const wxString
& s
) 
 727     verify_noerr ( HIComboBoxInsertTextItemAtIndex( *m_peer
, (CFIndex
) n
, 
 728         wxMacCFStringHolder(s
, m_font
.GetEncoding()) ) ); 
 729     verify_noerr ( HIComboBoxRemoveItemAtIndex( *m_peer
, (CFIndex
) n 
+ 1 ) ); 
 731     m_choice
->SetString( n 
, s 
) ; 
 735 bool wxComboBox::IsEditable() const 
 739     return !HasFlag(wxCB_READONLY
); 
 741     return m_text 
!= NULL 
&& !HasFlag(wxCB_READONLY
); 
 745 void wxComboBox::Undo() 
 755 void wxComboBox::Redo() 
 765 void wxComboBox::SelectAll() 
 775 bool wxComboBox::CanCopy() const 
 782         return m_text
->CanCopy(); 
 788 bool wxComboBox::CanCut() const 
 795         return m_text
->CanCut(); 
 801 bool wxComboBox::CanPaste() const 
 808         return m_text
->CanPaste(); 
 814 bool wxComboBox::CanUndo() const 
 821         return m_text
->CanUndo(); 
 827 bool wxComboBox::CanRedo() const 
 834         return m_text
->CanRedo(); 
 840 wxInt32 
wxComboBox::MacControlHit(WXEVENTHANDLERREF 
WXUNUSED(handler
) , WXEVENTREF 
WXUNUSED(event
) ) 
 842     wxCommandEvent 
event(wxEVT_COMMAND_COMBOBOX_SELECTED
, m_windowId 
); 
 843     event
.SetInt(GetSelection()); 
 844     event
.SetEventObject(this); 
 845     event
.SetString(GetStringSelection()); 
 846     ProcessCommand(event
);