1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/mac/carbon/combobox.cpp 
   3 // Purpose:     wxComboBox class 
   4 // Author:      Stefan Csomor, Dan "Bud" Keith (composite combobox) 
   8 // Copyright:   (c) Stefan Csomor 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #include "wx/wxprec.h" 
  16 #include "wx/combobox.h" 
  19     #include "wx/button.h" 
  21     #include "wx/containr.h" 
  22     #include "wx/toplevel.h" 
  25 #include "wx/mac/uma.h" 
  27 IMPLEMENT_DYNAMIC_CLASS(wxComboBox
, wxControl
) 
  29 WX_DELEGATE_TO_CONTROL_CONTAINER(wxComboBox
, wxControl
) 
  31 BEGIN_EVENT_TABLE(wxComboBox
, wxControl
) 
  32     WX_EVENT_TABLE_CONTROL_CONTAINER(wxComboBox
) 
  36 static int nextPopUpMenuId 
= 1000 ; 
  38 MenuHandle 
NewUniqueMenu() 
  40     MenuHandle handle 
= UMANewMenu(nextPopUpMenuId
, wxString(wxT("Menu")), wxFont::GetDefaultEncoding() ); 
  47 // ---------------------------------------------------------------------------- 
  49 // ---------------------------------------------------------------------------- 
  51 // the margin between the text control and the choice 
  52 #if TARGET_API_MAC_OSX 
  53 // margin should be bigger on OS X due to blue highlight 
  54 // around text control. 
  55 static const wxCoord MARGIN 
= 4; 
  56 // this is the border a focus rect on OSX is needing 
  57 static const int    TEXTFOCUSBORDER 
= 3 ; 
  59 static const wxCoord MARGIN 
= 2; 
  60 static const int    TEXTFOCUSBORDER 
= 0 ; 
  64 // ---------------------------------------------------------------------------- 
  65 // wxComboBoxText: text control forwards events to combobox 
  66 // ---------------------------------------------------------------------------- 
  68 class wxComboBoxText 
: public wxTextCtrl
 
  71     wxComboBoxText( wxComboBox 
* cb 
) 
  72         : wxTextCtrl( cb 
, 1 ) 
  75         SetTriggerOnSetValue( false ); 
  79     void OnChar( wxKeyEvent
& event 
) 
  81         // Allows processing the tab key to go to the next control 
  82         if (event
.GetKeyCode() == WXK_TAB
) 
  84             wxNavigationKeyEvent NavEvent
; 
  85             NavEvent
.SetEventObject(this); 
  86             NavEvent
.SetDirection(true); 
  87             NavEvent
.SetWindowChange(false); 
  89             // Get the parent of the combo and have it process the navigation? 
  90             if (m_cb
->GetParent()->GetEventHandler()->ProcessEvent(NavEvent
)) 
  94         // send the event to the combobox class in case the user has bound EVT_CHAR 
  95         wxKeyEvent 
kevt(event
); 
  96         kevt
.SetEventObject(m_cb
); 
  97         if (m_cb
->GetEventHandler()->ProcessEvent(kevt
)) 
  98             // If the event was handled and not skipped then we're done 
 101         if ( event
.GetKeyCode() == WXK_RETURN 
) 
 103             wxCommandEvent 
event(wxEVT_COMMAND_TEXT_ENTER
, m_cb
->GetId()); 
 104             event
.SetString( GetValue() ); 
 105             event
.SetInt( m_cb
->GetSelection() ); 
 106             event
.SetEventObject( m_cb 
); 
 108             // This will invoke the dialog default action, 
 109             // such as the clicking the default button. 
 110             if (!m_cb
->GetEventHandler()->ProcessEvent( event 
)) 
 112                 wxTopLevelWindow 
*tlw 
= wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow
); 
 113                 if ( tlw 
&& tlw
->GetDefaultItem() ) 
 115                     wxButton 
*def 
= wxDynamicCast(tlw
->GetDefaultItem(), wxButton
); 
 116                     if ( def 
&& def
->IsEnabled() ) 
 118                         wxCommandEvent 
event( wxEVT_COMMAND_BUTTON_CLICKED
, def
->GetId() ); 
 119                         event
.SetEventObject(def
); 
 131     void OnKeyUp( wxKeyEvent
& event 
) 
 133         event
.SetEventObject(m_cb
); 
 134         event
.SetId(m_cb
->GetId()); 
 135         if (! m_cb
->GetEventHandler()->ProcessEvent(event
)) 
 139     void OnKeyDown( wxKeyEvent
& event 
) 
 141         event
.SetEventObject(m_cb
); 
 142         event
.SetId(m_cb
->GetId()); 
 143         if (! m_cb
->GetEventHandler()->ProcessEvent(event
)) 
 147     void OnText( wxCommandEvent
& event 
) 
 149         event
.SetEventObject(m_cb
); 
 150         event
.SetId(m_cb
->GetId()); 
 151         if (! m_cb
->GetEventHandler()->ProcessEvent(event
)) 
 158     DECLARE_EVENT_TABLE() 
 161 BEGIN_EVENT_TABLE(wxComboBoxText
, wxTextCtrl
) 
 162     EVT_KEY_DOWN(wxComboBoxText::OnKeyDown
) 
 163     EVT_CHAR(wxComboBoxText::OnChar
) 
 164     EVT_KEY_UP(wxComboBoxText::OnKeyUp
) 
 165     EVT_TEXT(wxID_ANY
, wxComboBoxText::OnText
) 
 168 class wxComboBoxChoice 
: public wxChoice
 
 171     wxComboBoxChoice( wxComboBox 
*cb
, int style 
) 
 172         : wxChoice( cb 
, 1 , wxDefaultPosition 
, wxDefaultSize 
, 0 , NULL 
, style 
& (wxCB_SORT
) ) 
 177     int GetPopupWidth() const 
 179         switch ( GetWindowVariant() ) 
 181             case wxWINDOW_VARIANT_NORMAL 
: 
 182             case wxWINDOW_VARIANT_LARGE 
: 
 191     void OnChoice( wxCommandEvent
& e 
) 
 193         wxString    s 
= e
.GetString(); 
 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
); 
 202         // For consistency with MSW and GTK, also send a text updated event 
 203         // After all, the text is updated when a selection is made 
 204         wxCommandEvent 
TextEvent( wxEVT_COMMAND_TEXT_UPDATED
, m_cb
->GetId() ); 
 205         TextEvent
.SetString( m_cb
->GetStringSelection() ); 
 206         TextEvent
.SetEventObject( m_cb 
); 
 207         m_cb
->ProcessCommand( TextEvent 
); 
 210     virtual wxSize 
DoGetBestSize() const 
 212         wxSize sz 
= wxChoice::DoGetBestSize() ; 
 213         if (! m_cb
->HasFlag(wxCB_READONLY
) ) 
 214             sz
.x 
= GetPopupWidth() ; 
 222     friend class wxComboBox
; 
 224     DECLARE_EVENT_TABLE() 
 227 BEGIN_EVENT_TABLE(wxComboBoxChoice
, wxChoice
) 
 228     EVT_CHOICE(wxID_ANY
, wxComboBoxChoice::OnChoice
) 
 231 wxComboBox::~wxComboBox() 
 233     // delete client objects 
 236     // delete the controls now, don't leave them alive even though they would 
 237     // still be eventually deleted by our parent - but it will be too late, the 
 238     // user code expects them to be gone now 
 245     if (m_choice 
!= NULL
) 
 252 // ---------------------------------------------------------------------------- 
 254 // ---------------------------------------------------------------------------- 
 256 wxSize 
wxComboBox::DoGetBestSize() const 
 258     if (!m_choice 
&& !m_text
) 
 261     wxSize size 
= m_choice
->GetBestSize(); 
 263     if ( m_text 
!= NULL 
) 
 265         wxSize  sizeText 
= m_text
->GetBestSize(); 
 266         if (sizeText
.y 
> size
.y
) 
 269         size
.x 
= m_choice
->GetPopupWidth() + sizeText
.x 
+ MARGIN
; 
 270         size
.x 
+= TEXTFOCUSBORDER 
; 
 271         size
.y 
+= 2 * TEXTFOCUSBORDER 
; 
 275         // clipping is too tight 
 282 void wxComboBox::DoMoveWindow(int x
, int y
, int width
, int height
) 
 284     wxControl::DoMoveWindow( x
, y
, width 
, height 
); 
 286     if ( m_text 
== NULL 
) 
 288         // we might not be fully constructed yet, therefore watch out... 
 290             m_choice
->SetSize(0, 0 , width
, -1); 
 294         wxCoord wText 
= width 
- m_choice
->GetPopupWidth() - MARGIN
; 
 295         m_text
->SetSize(TEXTFOCUSBORDER
, TEXTFOCUSBORDER
, wText
, -1); 
 297         // put it at an inset of 1 to have outer area shadows drawn as well 
 298         m_choice
->SetSize(TEXTFOCUSBORDER 
+ wText 
+ MARGIN 
- 1 , TEXTFOCUSBORDER
, m_choice
->GetPopupWidth() , -1); 
 302 // ---------------------------------------------------------------------------- 
 303 // operations forwarded to the subcontrols 
 304 // ---------------------------------------------------------------------------- 
 306 bool wxComboBox::Enable(bool enable
) 
 308     if ( !wxControl::Enable(enable
) ) 
 312         m_text
->Enable(enable
); 
 317 bool wxComboBox::Show(bool show
) 
 319     if ( !wxControl::Show(show
) ) 
 325 void wxComboBox::DelegateTextChanged( const wxString
& value 
) 
 327     SetStringSelection( value 
); 
 330 void wxComboBox::DelegateChoice( const wxString
& value 
) 
 332     SetStringSelection( value 
); 
 335 void wxComboBox::Init() 
 337     m_container
.SetContainerWindow(this); 
 340 bool wxComboBox::Create(wxWindow 
*parent
, 
 342     const wxString
& value
, 
 345     const wxArrayString
& choices
, 
 347     const wxValidator
& validator
, 
 348     const wxString
& name
) 
 350     wxCArrayString 
chs( choices 
); 
 352     return Create( parent
, id
, value
, pos
, size
, chs
.GetCount(), 
 353                    chs
.GetStrings(), style
, validator
, name 
); 
 356 bool wxComboBox::Create(wxWindow 
*parent
, 
 358     const wxString
& value
, 
 362     const wxString choices
[], 
 364     const wxValidator
& validator
, 
 365     const wxString
& name
) 
 367     if ( !wxControl::Create(parent
, id
, wxDefaultPosition
, wxDefaultSize
, style 
, 
 373     m_choice 
= new wxComboBoxChoice(this, style 
); 
 375     if ( style 
& wxCB_READONLY 
) 
 381         m_text 
= new wxComboBoxText(this); 
 384             csize
.y 
= m_text
->GetSize().y 
; 
 385             csize
.y 
+= 2 * TEXTFOCUSBORDER 
; 
 389     DoSetSize(pos
.x
, pos
.y
, csize
.x
, csize
.y
); 
 391     for ( int i 
= 0 ; i 
< n 
; i
++ ) 
 393         m_choice
->DoAppend( choices
[ i 
] ); 
 396     // Needed because it is a wxControlWithItems 
 397     SetInitialSize(size
); 
 398     SetStringSelection(value
); 
 403 wxString 
wxComboBox::GetValue() const 
 407     if ( m_text 
== NULL 
) 
 408         result 
= m_choice
->GetString( m_choice
->GetSelection() ); 
 410         result 
= m_text
->GetValue(); 
 415 unsigned int wxComboBox::GetCount() const 
 417     return m_choice
->GetCount() ; 
 420 void wxComboBox::SetValue(const wxString
& value
) 
 422     if ( HasFlag(wxCB_READONLY
) ) 
 423         SetStringSelection( value 
) ; 
 425         m_text
->SetValue( value 
); 
 428 // Clipboard operations 
 430 void wxComboBox::Copy() 
 432     if ( m_text 
!= NULL 
) 
 436 void wxComboBox::Cut() 
 438     if ( m_text 
!= NULL 
) 
 442 void wxComboBox::Paste() 
 444     if ( m_text 
!= NULL 
) 
 448 void wxComboBox::SetEditable(bool editable
) 
 450     if ( ( m_text 
== NULL 
) && editable 
) 
 452         m_text 
= new wxComboBoxText( this ); 
 454     else if ( ( m_text 
!= NULL 
) && !editable 
) 
 460     int currentX
, currentY
; 
 461     GetPosition( ¤tX
, ¤tY 
); 
 463     int currentW
, currentH
; 
 464     GetSize( ¤tW
, ¤tH 
); 
 466     DoMoveWindow( currentX
, currentY
, currentW
, currentH 
); 
 469 void wxComboBox::SetInsertionPoint(long pos
) 
 472         m_text
->SetInsertionPoint(pos
); 
 475 void wxComboBox::SetInsertionPointEnd() 
 478         m_text
->SetInsertionPointEnd(); 
 481 long wxComboBox::GetInsertionPoint() const 
 484         return m_text
->GetInsertionPoint(); 
 488 wxTextPos 
wxComboBox::GetLastPosition() const 
 491         return m_text
->GetLastPosition(); 
 495 void wxComboBox::Replace(long from
, long to
, const wxString
& value
) 
 498         m_text
->Replace(from
,to
,value
); 
 501 void wxComboBox::Remove(long from
, long to
) 
 504         m_text
->Remove(from
,to
); 
 507 void wxComboBox::SetSelection(long from
, long to
) 
 510         m_text
->SetSelection(from
,to
); 
 513 int wxComboBox::DoAppend(const wxString
& item
) 
 515     return m_choice
->DoAppend( item 
) ; 
 518 int wxComboBox::DoInsert(const wxString
& item
, unsigned int pos
) 
 520     return m_choice
->DoInsert( item 
, pos 
) ; 
 523 void wxComboBox::DoSetItemClientData(unsigned int n
, void* clientData
) 
 525     return m_choice
->DoSetItemClientData( n 
, clientData 
) ; 
 528 void* wxComboBox::DoGetItemClientData(unsigned int n
) const 
 530     return m_choice
->DoGetItemClientData( n 
) ; 
 533 void wxComboBox::DoSetItemClientObject(unsigned int n
, wxClientData
* clientData
) 
 535     return m_choice
->DoSetItemClientObject(n
, clientData
); 
 538 wxClientData
* wxComboBox::DoGetItemClientObject(unsigned int n
) const 
 540     return m_choice
->DoGetItemClientObject( n 
) ; 
 543 void wxComboBox::FreeData() 
 545     if ( HasClientObjectData() ) 
 547         unsigned int count 
= GetCount(); 
 548         for ( unsigned int n 
= 0; n 
< count
; n
++ ) 
 550             SetClientObject( n
, NULL 
); 
 555 void wxComboBox::Delete(unsigned int n
) 
 557     // force client object deletion 
 558     if( HasClientObjectData() ) 
 559         SetClientObject( n
, NULL 
); 
 560     m_choice
->Delete( n 
); 
 563 void wxComboBox::Clear() 
 569 int wxComboBox::GetSelection() const 
 571     return m_choice
->GetSelection(); 
 574 void wxComboBox::SetSelection(int n
) 
 576     m_choice
->SetSelection( n 
); 
 578     if ( m_text 
!= NULL 
) 
 579         m_text
->SetValue(GetString(n
)); 
 582 int wxComboBox::FindString(const wxString
& s
, bool bCase
) const 
 584     return m_choice
->FindString( s
, bCase 
); 
 587 wxString 
wxComboBox::GetString(unsigned int n
) const 
 589     return m_choice
->GetString( n 
); 
 592 wxString 
wxComboBox::GetStringSelection() const 
 594     int sel 
= GetSelection(); 
 595     if (sel 
!= wxNOT_FOUND
) 
 596         return wxString(this->GetString((unsigned int)sel
)); 
 598         return wxEmptyString
; 
 601 void wxComboBox::SetString(unsigned int n
, const wxString
& s
) 
 603     m_choice
->SetString( n 
, s 
); 
 606 bool wxComboBox::IsEditable() const 
 608     return m_text 
!= NULL 
&& !HasFlag(wxCB_READONLY
); 
 611 void wxComboBox::Undo() 
 617 void wxComboBox::Redo() 
 623 void wxComboBox::SelectAll() 
 629 bool wxComboBox::CanCopy() const 
 632         return m_text
->CanCopy(); 
 637 bool wxComboBox::CanCut() const 
 640         return m_text
->CanCut(); 
 645 bool wxComboBox::CanPaste() const 
 648         return m_text
->CanPaste(); 
 653 bool wxComboBox::CanUndo() const 
 656         return m_text
->CanUndo(); 
 661 bool wxComboBox::CanRedo() const 
 664         return m_text
->CanRedo(); 
 669 wxInt32 
wxComboBox::MacControlHit( WXEVENTHANDLERREF 
WXUNUSED(handler
) , WXEVENTREF 
WXUNUSED(event
) ) 
 672     For consistency with other platforms, clicking in the text area does not constitute a selection 
 673     wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, m_windowId ); 
 674     event.SetInt(GetSelection()); 
 675     event.SetEventObject(this); 
 676     event.SetString(GetStringSelection()); 
 677     ProcessCommand(event); 
 683 #endif // wxUSE_COMBOBOX