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" 
  23     #include "wx/textctrl.h" 
  26 #include "wx/mac/uma.h" 
  28 IMPLEMENT_DYNAMIC_CLASS(wxComboBox
, wxControl
) 
  30 WX_DELEGATE_TO_CONTROL_CONTAINER(wxComboBox
, wxControl
) 
  32 BEGIN_EVENT_TABLE(wxComboBox
, wxControl
) 
  33     WX_EVENT_TABLE_CONTROL_CONTAINER(wxComboBox
) 
  37 static int nextPopUpMenuId 
= 1000 ; 
  39 MenuHandle 
NewUniqueMenu() 
  41     MenuHandle handle 
= UMANewMenu(nextPopUpMenuId
, wxString(wxT("Menu")), wxFont::GetDefaultEncoding() ); 
  48 // ---------------------------------------------------------------------------- 
  50 // ---------------------------------------------------------------------------- 
  52 // the margin between the text control and the choice 
  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 ; 
  60 // ---------------------------------------------------------------------------- 
  61 // wxComboBoxText: text control forwards events to combobox 
  62 // ---------------------------------------------------------------------------- 
  64 class wxComboBoxText 
: public wxTextCtrl
 
  67     wxComboBoxText( wxComboBox 
* cb 
) 
  68         : wxTextCtrl( cb 
, 1 ) 
  71         SetTriggerOnSetValue( false ); 
  75     void OnChar( wxKeyEvent
& event 
) 
  77         // Allows processing the tab key to go to the next control 
  78         if (event
.GetKeyCode() == WXK_TAB
) 
  80             wxNavigationKeyEvent NavEvent
; 
  81             NavEvent
.SetEventObject(this); 
  82             NavEvent
.SetDirection(true); 
  83             NavEvent
.SetWindowChange(false); 
  85             // Get the parent of the combo and have it process the navigation? 
  86             if (m_cb
->GetParent()->HandleWindowEvent(NavEvent
)) 
  90         // send the event to the combobox class in case the user has bound EVT_CHAR 
  91         wxKeyEvent 
kevt(event
); 
  92         kevt
.SetEventObject(m_cb
); 
  93         if (m_cb
->HandleWindowEvent(kevt
)) 
  94             // If the event was handled and not skipped then we're done 
  97         if ( event
.GetKeyCode() == WXK_RETURN 
) 
  99             wxCommandEvent 
event(wxEVT_COMMAND_TEXT_ENTER
, m_cb
->GetId()); 
 100             event
.SetString( GetValue() ); 
 101             event
.SetInt( m_cb
->GetSelection() ); 
 102             event
.SetEventObject( m_cb 
); 
 104             // This will invoke the dialog default action, 
 105             // such as the clicking the default button. 
 106             if (!m_cb
->HandleWindowEvent( event 
)) 
 108                 wxTopLevelWindow 
*tlw 
= wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow
); 
 109                 if ( tlw 
&& tlw
->GetDefaultItem() ) 
 111                     wxButton 
*def 
= wxDynamicCast(tlw
->GetDefaultItem(), wxButton
); 
 112                     if ( def 
&& def
->IsEnabled() ) 
 114                         wxCommandEvent 
event( wxEVT_COMMAND_BUTTON_CLICKED
, def
->GetId() ); 
 115                         event
.SetEventObject(def
); 
 127     void OnKeyUp( wxKeyEvent
& event 
) 
 129         event
.SetEventObject(m_cb
); 
 130         event
.SetId(m_cb
->GetId()); 
 131         if (! m_cb
->HandleWindowEvent(event
)) 
 135     void OnKeyDown( wxKeyEvent
& event 
) 
 137         event
.SetEventObject(m_cb
); 
 138         event
.SetId(m_cb
->GetId()); 
 139         if (! m_cb
->HandleWindowEvent(event
)) 
 143     void OnText( wxCommandEvent
& event 
) 
 145         event
.SetEventObject(m_cb
); 
 146         event
.SetId(m_cb
->GetId()); 
 147         if (! m_cb
->HandleWindowEvent(event
)) 
 154     DECLARE_EVENT_TABLE() 
 157 BEGIN_EVENT_TABLE(wxComboBoxText
, wxTextCtrl
) 
 158     EVT_KEY_DOWN(wxComboBoxText::OnKeyDown
) 
 159     EVT_CHAR(wxComboBoxText::OnChar
) 
 160     EVT_KEY_UP(wxComboBoxText::OnKeyUp
) 
 161     EVT_TEXT(wxID_ANY
, wxComboBoxText::OnText
) 
 164 class wxComboBoxChoice 
: public wxChoice
 
 167     wxComboBoxChoice( wxComboBox 
*cb
, int style 
) 
 168         : wxChoice( cb 
, 1 , wxDefaultPosition 
, wxDefaultSize 
, 0 , NULL 
, style 
& (wxCB_SORT
) ) 
 173     int GetPopupWidth() const 
 175         switch ( GetWindowVariant() ) 
 177             case wxWINDOW_VARIANT_NORMAL 
: 
 178             case wxWINDOW_VARIANT_LARGE 
: 
 187     void OnChoice( wxCommandEvent
& e 
) 
 189         wxString    s 
= e
.GetString(); 
 191         m_cb
->DelegateChoice( s 
); 
 192         wxCommandEvent 
event2(wxEVT_COMMAND_COMBOBOX_SELECTED
, m_cb
->GetId() ); 
 193         event2
.SetInt(m_cb
->GetSelection()); 
 194         event2
.SetEventObject(m_cb
); 
 195         event2
.SetString(m_cb
->GetStringSelection()); 
 196         m_cb
->ProcessCommand(event2
); 
 198         // For consistency with MSW and GTK, also send a text updated event 
 199         // After all, the text is updated when a selection is made 
 200         wxCommandEvent 
TextEvent( wxEVT_COMMAND_TEXT_UPDATED
, m_cb
->GetId() ); 
 201         TextEvent
.SetString( m_cb
->GetStringSelection() ); 
 202         TextEvent
.SetEventObject( m_cb 
); 
 203         m_cb
->ProcessCommand( TextEvent 
); 
 206     virtual wxSize 
DoGetBestSize() const 
 208         wxSize sz 
= wxChoice::DoGetBestSize() ; 
 209         if (! m_cb
->HasFlag(wxCB_READONLY
) ) 
 210             sz
.x 
= GetPopupWidth() ; 
 218     friend class wxComboBox
; 
 220     DECLARE_EVENT_TABLE() 
 223 BEGIN_EVENT_TABLE(wxComboBoxChoice
, wxChoice
) 
 224     EVT_CHOICE(wxID_ANY
, wxComboBoxChoice::OnChoice
) 
 227 wxComboBox::~wxComboBox() 
 229     // delete the controls now, don't leave them alive even though they would 
 230     // still be eventually deleted by our parent - but it will be too late, the 
 231     // user code expects them to be gone now 
 238     if (m_choice 
!= NULL
) 
 245 // ---------------------------------------------------------------------------- 
 247 // ---------------------------------------------------------------------------- 
 249 wxSize 
wxComboBox::DoGetBestSize() const 
 251     if (!m_choice 
&& !m_text
) 
 254     wxSize size 
= m_choice
->GetBestSize(); 
 256     if ( m_text 
!= NULL 
) 
 258         wxSize  sizeText 
= m_text
->GetBestSize(); 
 259         if (sizeText
.y 
> size
.y
) 
 262         size
.x 
= m_choice
->GetPopupWidth() + sizeText
.x 
+ MARGIN
; 
 263         size
.x 
+= TEXTFOCUSBORDER 
; 
 264         size
.y 
+= 2 * TEXTFOCUSBORDER 
; 
 268         // clipping is too tight 
 275 void wxComboBox::DoMoveWindow(int x
, int y
, int width
, int height
) 
 277     wxControl::DoMoveWindow( x
, y
, width 
, height 
); 
 279     if ( m_text 
== NULL 
) 
 281         // we might not be fully constructed yet, therefore watch out... 
 283             m_choice
->SetSize(0, 0 , width
, -1); 
 287         wxCoord wText 
= width 
- m_choice
->GetPopupWidth() - MARGIN
; 
 288         m_text
->SetSize(TEXTFOCUSBORDER
, TEXTFOCUSBORDER
, wText
, -1); 
 290         // put it at an inset of 1 to have outer area shadows drawn as well 
 291         m_choice
->SetSize(TEXTFOCUSBORDER 
+ wText 
+ MARGIN 
- 1 , TEXTFOCUSBORDER
, m_choice
->GetPopupWidth() , -1); 
 295 // ---------------------------------------------------------------------------- 
 296 // operations forwarded to the subcontrols 
 297 // ---------------------------------------------------------------------------- 
 299 bool wxComboBox::Enable(bool enable
) 
 301     if ( !wxControl::Enable(enable
) ) 
 305         m_text
->Enable(enable
); 
 310 bool wxComboBox::Show(bool show
) 
 312     if ( !wxControl::Show(show
) ) 
 318 void wxComboBox::DelegateTextChanged( const wxString
& value 
) 
 320     SetStringSelection( value 
); 
 323 void wxComboBox::DelegateChoice( const wxString
& value 
) 
 325     SetStringSelection( value 
); 
 328 void wxComboBox::Init() 
 330     WX_INIT_CONTROL_CONTAINER(); 
 333 bool wxComboBox::Create(wxWindow 
*parent
, 
 335     const wxString
& value
, 
 338     const wxArrayString
& choices
, 
 340     const wxValidator
& validator
, 
 341     const wxString
& name
) 
 343     if ( !Create( parent
, id
, value
, pos
, size
, 0, NULL
, 
 344                    style
, validator
, name 
) ) 
 352 bool wxComboBox::Create(wxWindow 
*parent
, 
 354     const wxString
& value
, 
 358     const wxString choices
[], 
 360     const wxValidator
& validator
, 
 361     const wxString
& name
) 
 363     if ( !wxControl::Create(parent
, id
, wxDefaultPosition
, wxDefaultSize
, style 
, 
 369     m_choice 
= new wxComboBoxChoice(this, style 
); 
 371     if ( style 
& wxCB_READONLY 
) 
 377         m_text 
= new wxComboBoxText(this); 
 380             csize
.y 
= m_text
->GetSize().y 
; 
 381             csize
.y 
+= 2 * TEXTFOCUSBORDER 
; 
 385     DoSetSize(pos
.x
, pos
.y
, csize
.x
, csize
.y
); 
 387     Append( n
, choices 
); 
 389     // Needed because it is a wxControlWithItems 
 390     SetInitialSize(size
); 
 391     SetStringSelection(value
); 
 396 wxString 
wxComboBox::GetValue() const 
 400     if ( m_text 
== NULL 
) 
 401         result 
= m_choice
->GetString( m_choice
->GetSelection() ); 
 403         result 
= m_text
->GetValue(); 
 408 unsigned int wxComboBox::GetCount() const 
 410     return m_choice
->GetCount() ; 
 413 void wxComboBox::SetValue(const wxString
& value
) 
 415     if ( HasFlag(wxCB_READONLY
) ) 
 416         SetStringSelection( value 
) ; 
 418         m_text
->SetValue( value 
); 
 421 void wxComboBox::WriteText(const wxString
& text
) 
 423     m_text
->WriteText(text
); 
 426 void wxComboBox::GetSelection(long *from
, long *to
) const 
 428     m_text
->GetSelection(from
, to
); 
 431 // Clipboard operations 
 433 void wxComboBox::Copy() 
 435     if ( m_text 
!= NULL 
) 
 439 void wxComboBox::Cut() 
 441     if ( m_text 
!= NULL 
) 
 445 void wxComboBox::Paste() 
 447     if ( m_text 
!= NULL 
) 
 451 void wxComboBox::SetEditable(bool editable
) 
 453     if ( ( m_text 
== NULL 
) && editable 
) 
 455         m_text 
= new wxComboBoxText( this ); 
 457     else if ( ( m_text 
!= NULL 
) && !editable 
) 
 463     int currentX
, currentY
; 
 464     GetPosition( ¤tX
, ¤tY 
); 
 466     int currentW
, currentH
; 
 467     GetSize( ¤tW
, ¤tH 
); 
 469     DoMoveWindow( currentX
, currentY
, currentW
, currentH 
); 
 472 void wxComboBox::SetInsertionPoint(long pos
) 
 475         m_text
->SetInsertionPoint(pos
); 
 478 void wxComboBox::SetInsertionPointEnd() 
 481         m_text
->SetInsertionPointEnd(); 
 484 long wxComboBox::GetInsertionPoint() const 
 487         return m_text
->GetInsertionPoint(); 
 491 wxTextPos 
wxComboBox::GetLastPosition() const 
 494         return m_text
->GetLastPosition(); 
 498 void wxComboBox::Replace(long from
, long to
, const wxString
& value
) 
 501         m_text
->Replace(from
,to
,value
); 
 504 void wxComboBox::Remove(long from
, long to
) 
 507         m_text
->Remove(from
,to
); 
 510 void wxComboBox::SetSelection(long from
, long to
) 
 513         m_text
->SetSelection(from
,to
); 
 516 int wxComboBox::DoInsertItems(const wxArrayStringsAdapter
& items
, 
 519                               wxClientDataType type
) 
 521     return m_choice
->DoInsertItems(items
, pos
, clientData
, type
); 
 524 void wxComboBox::DoSetItemClientData(unsigned int n
, void* clientData
) 
 526     return m_choice
->DoSetItemClientData( n 
, clientData 
) ; 
 529 void* wxComboBox::DoGetItemClientData(unsigned int n
) const 
 531     return m_choice
->DoGetItemClientData( n 
) ; 
 534 wxClientDataType 
wxComboBox::GetClientDataType() const 
 536     return m_choice
->GetClientDataType(); 
 539 void wxComboBox::SetClientDataType(wxClientDataType clientDataItemsType
) 
 541     m_choice
->SetClientDataType(clientDataItemsType
); 
 544 void wxComboBox::DoDeleteOneItem(unsigned int n
) 
 546     m_choice
->DoDeleteOneItem( n 
); 
 549 void wxComboBox::DoClear() 
 554 int wxComboBox::GetSelection() const 
 556     return m_choice
->GetSelection(); 
 559 void wxComboBox::SetSelection(int n
) 
 561     m_choice
->SetSelection( n 
); 
 563     if ( m_text 
!= NULL 
) 
 564         m_text
->SetValue(n 
!= wxNOT_FOUND 
? GetString(n
) : wxString(wxEmptyString
)); 
 567 int wxComboBox::FindString(const wxString
& s
, bool bCase
) const 
 569     return m_choice
->FindString( s
, bCase 
); 
 572 wxString 
wxComboBox::GetString(unsigned int n
) const 
 574     return m_choice
->GetString( n 
); 
 577 wxString 
wxComboBox::GetStringSelection() const 
 579     int sel 
= GetSelection(); 
 580     if (sel 
!= wxNOT_FOUND
) 
 581         return wxString(this->GetString((unsigned int)sel
)); 
 583         return wxEmptyString
; 
 586 void wxComboBox::SetString(unsigned int n
, const wxString
& s
) 
 588     m_choice
->SetString( n 
, s 
); 
 591 bool wxComboBox::IsEditable() const 
 593     return m_text 
!= NULL 
&& !HasFlag(wxCB_READONLY
); 
 596 void wxComboBox::Undo() 
 602 void wxComboBox::Redo() 
 608 void wxComboBox::SelectAll() 
 614 bool wxComboBox::CanCopy() const 
 617         return m_text
->CanCopy(); 
 622 bool wxComboBox::CanCut() const 
 625         return m_text
->CanCut(); 
 630 bool wxComboBox::CanPaste() const 
 633         return m_text
->CanPaste(); 
 638 bool wxComboBox::CanUndo() const 
 641         return m_text
->CanUndo(); 
 646 bool wxComboBox::CanRedo() const 
 649         return m_text
->CanRedo(); 
 654 wxInt32 
wxComboBox::MacControlHit( WXEVENTHANDLERREF 
WXUNUSED(handler
) , WXEVENTREF 
WXUNUSED(event
) ) 
 657     For consistency with other platforms, clicking in the text area does not constitute a selection 
 658     wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, m_windowId ); 
 659     event.SetInt(GetSelection()); 
 660     event.SetEventObject(this); 
 661     event.SetString(GetStringSelection()); 
 662     ProcessCommand(event); 
 668 #endif // wxUSE_COMBOBOX