1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxComboBox class
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "combobox.h"
16 #include "wx/combobox.h"
17 #include "wx/button.h"
19 #include "wx/mac/uma.h"
21 #include <HIToolbox/HIView.h>
24 #if !USE_SHARED_LIBRARY
25 IMPLEMENT_DYNAMIC_CLASS(wxComboBox
, wxControl
)
28 // composite combobox implementation by Dan "Bud" Keith bud@otsys.com
30 #define USE_HICOMBOBOX 1 //use hi combobox define
32 static int nextPopUpMenuId
= 1000 ;
33 MenuHandle
NewUniqueMenu()
35 MenuHandle handle
= NewMenu( nextPopUpMenuId
, "\pMenu" ) ;
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 // the margin between the text control and the choice
46 static const wxCoord MARGIN
= 2;
47 #if TARGET_API_MAC_OSX
48 static const int POPUPWIDTH
= 24;
50 static const int POPUPWIDTH
= 18;
52 static const int POPUPHEIGHT
= 23;
54 // ----------------------------------------------------------------------------
55 // wxComboBoxText: text control forwards events to combobox
56 // ----------------------------------------------------------------------------
58 class wxComboBoxText
: public wxTextCtrl
61 wxComboBoxText( wxComboBox
* cb
)
62 : wxTextCtrl( cb
, 1 )
68 void OnChar( wxKeyEvent
& event
)
70 if ( event
.GetKeyCode() == WXK_RETURN
)
72 wxString value
= GetValue();
74 if ( m_cb
->GetCount() == 0 )
76 // make Enter generate "selected" event if there is only one item
77 // in the combobox - without it, it's impossible to select it at
79 wxCommandEvent
event( wxEVT_COMMAND_COMBOBOX_SELECTED
, m_cb
->GetId() );
81 event
.SetString( value
);
82 event
.SetEventObject( m_cb
);
83 m_cb
->GetEventHandler()->ProcessEvent( event
);
87 // add the item to the list if it's not there yet
88 if ( m_cb
->FindString(value
) == wxNOT_FOUND
)
91 m_cb
->SetStringSelection(value
);
93 // and generate the selected event for it
94 wxCommandEvent
event( wxEVT_COMMAND_COMBOBOX_SELECTED
, m_cb
->GetId() );
95 event
.SetInt( m_cb
->GetCount() - 1 );
96 event
.SetString( value
);
97 event
.SetEventObject( m_cb
);
98 m_cb
->GetEventHandler()->ProcessEvent( event
);
101 // This will invoke the dialog default action, such
102 // as the clicking the default button.
104 wxWindow
*parent
= GetParent();
105 while( parent
&& !parent
->IsTopLevel() && parent
->GetDefaultItem() == NULL
) {
106 parent
= parent
->GetParent() ;
108 if ( parent
&& parent
->GetDefaultItem() )
110 wxButton
*def
= wxDynamicCast(parent
->GetDefaultItem(),
112 if ( def
&& def
->IsEnabled() )
114 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, def
->GetId() );
115 event
.SetEventObject(def
);
130 DECLARE_EVENT_TABLE()
133 BEGIN_EVENT_TABLE(wxComboBoxText
, wxTextCtrl
)
134 EVT_CHAR( wxComboBoxText::OnChar
)
137 class wxComboBoxChoice
: public wxChoice
140 wxComboBoxChoice(wxComboBox
*cb
, int style
)
147 void OnChoice( wxCommandEvent
& e
)
149 wxString s
= e
.GetString();
151 m_cb
->DelegateChoice( s
);
152 wxCommandEvent
event2(wxEVT_COMMAND_COMBOBOX_SELECTED
, m_cb
->GetId() );
153 event2
.SetInt(m_cb
->GetSelection());
154 event2
.SetEventObject(m_cb
);
155 event2
.SetString(m_cb
->GetStringSelection());
156 m_cb
->ProcessCommand(event2
);
158 virtual wxSize
DoGetBestSize() const
160 wxSize sz
= wxChoice::DoGetBestSize() ;
168 DECLARE_EVENT_TABLE()
171 BEGIN_EVENT_TABLE(wxComboBoxChoice
, wxChoice
)
172 EVT_CHOICE(-1, wxComboBoxChoice::OnChoice
)
175 wxComboBox::~wxComboBox()
177 // delete client objects
180 // delete the controls now, don't leave them alive even though they would
181 // still be eventually deleted by our parent - but it will be too late, the
182 // user code expects them to be gone now
183 if (m_text
!= NULL
) {
187 if (m_choice
!= NULL
) {
194 // ----------------------------------------------------------------------------
196 // ----------------------------------------------------------------------------
198 wxSize
wxComboBox::DoGetBestSize() const
201 return wxControl::DoGetBestSize();
203 wxSize size
= m_choice
->GetBestSize();
205 if ( m_text
!= NULL
)
207 wxSize sizeText
= m_text
->GetBestSize();
209 size
.x
= POPUPWIDTH
+ sizeText
.x
+ MARGIN
;
216 void wxComboBox::DoMoveWindow(int x
, int y
, int width
, int height
) {
218 wxControl::DoMoveWindow(x
, y
, width
, height
);
220 height
= POPUPHEIGHT
;
222 wxControl::DoMoveWindow(x
, y
, width
, height
);
224 if ( m_text
== NULL
)
226 // we might not be fully constructed yet, therefore watch out...
228 m_choice
->SetSize(0, 0 , width
, -1);
232 wxCoord wText
= width
- POPUPWIDTH
- MARGIN
;
233 m_text
->SetSize(0, 0, wText
, height
);
234 m_choice
->SetSize(0 + wText
+ MARGIN
, 0, POPUPWIDTH
, -1);
241 // ----------------------------------------------------------------------------
242 // operations forwarded to the subcontrols
243 // ----------------------------------------------------------------------------
245 bool wxComboBox::Enable(bool enable
)
247 if ( !wxControl::Enable(enable
) )
253 bool wxComboBox::Show(bool show
)
255 if ( !wxControl::Show(show
) )
261 void wxComboBox::SetFocus()
264 wxControl::SetFocus();
266 if ( m_text
!= NULL
) {
273 void wxComboBox::DelegateTextChanged( const wxString
& value
)
275 SetStringSelection( value
);
279 void wxComboBox::DelegateChoice( const wxString
& value
)
281 SetStringSelection( value
);
285 bool wxComboBox::Create(wxWindow
*parent
, wxWindowID id
,
286 const wxString
& value
,
289 const wxArrayString
& choices
,
291 const wxValidator
& validator
,
292 const wxString
& name
)
294 wxCArrayString
chs( choices
);
296 return Create( parent
, id
, value
, pos
, size
, chs
.GetCount(),
297 chs
.GetStrings(), style
, validator
, name
);
301 bool wxComboBox::Create(wxWindow
*parent
, wxWindowID id
,
302 const wxString
& value
,
305 int n
, const wxString choices
[],
307 const wxValidator
& validator
,
308 const wxString
& name
)
313 m_macIsUserPane
= FALSE
;
315 if ( !wxControl::Create(parent
, id
, wxDefaultPosition
, wxDefaultSize
, style
,
316 wxDefaultValidator
, name
) )
321 Rect bounds
= wxMacGetBoundsForControl( this , pos
, size
) ;
324 hiRect
.origin
.x
= 20; //bounds.left;
325 hiRect
.origin
.y
= 25; //bounds.top;
326 hiRect
.size
.width
= 120;// bounds.right - bounds.left;
327 hiRect
.size
.height
= 24;
329 //For some reason, this code causes the combo box not to be displayed at all.
330 //hiRect.origin.x = bounds.left;
331 //hiRect.origin.y = bounds.top;
332 //hiRect.size.width = bounds.right - bounds.left;
333 //hiRect.size.height = bounds.bottom - bounds.top;
334 //printf("left = %d, right = %d, top = %d, bottom = %d\n", bounds.left, bounds.right, bounds.top, bounds.bottom);
335 //printf("x = %d, y = %d, width = %d, height = %d\n", hibounds.origin.x, hibounds.origin.y, hibounds.size.width, hibounds.size.height);
336 verify_noerr( HIComboBoxCreate( &hiRect
, CFSTR(""), NULL
, NULL
, kHIComboBoxStandardAttributes
, (HIViewRef
*) &m_macControl
) );
338 SetControl32BitMinimum( (ControlRef
) m_macControl
, 0 ) ;
339 SetControl32BitMaximum( (ControlRef
) m_macControl
, 100) ;
341 SetControl32BitValue( (ControlRef
) m_macControl
, 1 ) ;
343 MacPostControlCreate(pos
,size
) ;
345 for ( int i
= 0 ; i
< n
; i
++ )
347 DoAppend( choices
[ i
] );
350 HIViewSetVisible( (HIViewRef
) m_macControl
, true );
353 m_choice
= new wxComboBoxChoice(this, style
);
355 m_choice
= new wxComboBoxChoice(this, style
);
356 m_choice
->SetSizeHints( wxSize( POPUPWIDTH
, POPUPHEIGHT
) ) ;
359 if ( style
& wxCB_READONLY
)
365 m_text
= new wxComboBoxText(this);
366 if ( size
.y
== -1 ) {
367 csize
.y
= m_text
->GetSize().y
;
371 DoSetSize(pos
.x
, pos
.y
, csize
.x
, csize
.y
);
373 for ( int i
= 0 ; i
< n
; i
++ )
375 m_choice
->DoAppend( choices
[ i
] );
377 SetBestSize(csize
); // Needed because it is a wxControlWithItems
383 wxString
wxComboBox::GetValue() const
386 CFStringRef myString
;
387 HIComboBoxCopyTextItemAtIndex( (HIViewRef
) m_macControl
, (CFIndex
)GetSelection(), &myString
);
388 return wxMacCFStringHolder( myString
, m_font
.GetEncoding() ).AsString();
392 if ( m_text
== NULL
)
394 result
= m_choice
->GetString( m_choice
->GetSelection() );
398 result
= m_text
->GetValue();
405 void wxComboBox::SetValue(const wxString
& value
)
410 int s
= FindString (value
);
411 if (s
== wxNOT_FOUND
&& !HasFlag(wxCB_READONLY
) )
413 m_choice
->Append(value
) ;
415 SetStringSelection( value
) ;
419 // Clipboard operations
420 void wxComboBox::Copy()
422 if ( m_text
!= NULL
)
428 void wxComboBox::Cut()
430 if ( m_text
!= NULL
)
436 void wxComboBox::Paste()
438 if ( m_text
!= NULL
)
444 void wxComboBox::SetEditable(bool editable
)
446 if ( ( m_text
== NULL
) && editable
)
448 m_text
= new wxComboBoxText( this );
450 else if ( ( m_text
!= NULL
) && !editable
)
456 int currentX
, currentY
;
457 GetPosition( ¤tX
, ¤tY
);
459 int currentW
, currentH
;
460 GetSize( ¤tW
, ¤tH
);
462 DoMoveWindow( currentX
, currentY
, currentW
, currentH
);
465 void wxComboBox::SetInsertionPoint(long pos
)
470 void wxComboBox::SetInsertionPointEnd()
475 long wxComboBox::GetInsertionPoint() const
481 long wxComboBox::GetLastPosition() const
487 void wxComboBox::Replace(long from
, long to
, const wxString
& value
)
492 void wxComboBox::Remove(long from
, long to
)
497 void wxComboBox::SetSelection(long from
, long to
)
502 int wxComboBox::DoAppend(const wxString
& item
)
506 HIComboBoxAppendTextItem( (HIViewRef
) m_macControl
, wxMacCFStringHolder( item
, m_font
.GetEncoding() ), &outIndex
);
507 //SetControl32BitMaximum( (HIViewRef) m_macControl, GetCount() );
508 return (int) outIndex
;
510 return m_choice
->DoAppend( item
) ;
514 int wxComboBox::DoInsert(const wxString
& item
, int pos
)
517 HIComboBoxInsertTextItemAtIndex( (HIViewRef
) m_macControl
, (CFIndex
)pos
, wxMacCFStringHolder(item
, m_font
.GetEncoding()) );
519 //SetControl32BitMaximum( (HIViewRef) m_macControl, GetCount() );
523 return m_choice
->DoInsert( item
, pos
) ;
527 void wxComboBox::DoSetItemClientData(int n
, void* clientData
)
532 return m_choice
->DoSetItemClientData( n
, clientData
) ;
536 void* wxComboBox::DoGetItemClientData(int n
) const
541 return m_choice
->DoGetItemClientData( n
) ;
545 void wxComboBox::DoSetItemClientObject(int n
, wxClientData
* clientData
)
550 return m_choice
->DoSetItemClientObject( n
, clientData
) ;
554 wxClientData
* wxComboBox::DoGetItemClientObject(int n
) const
559 return m_choice
->DoGetItemClientObject( n
) ;
563 void wxComboBox::FreeData()
565 if ( HasClientObjectData() )
567 size_t count
= GetCount();
568 for ( size_t n
= 0; n
< count
; n
++ )
570 SetClientObject( n
, NULL
);
575 int wxComboBox::GetCount() const {
577 return (int) HIComboBoxGetItemCount( (HIViewRef
) m_macControl
);
579 return m_choice
->GetCount() ;
583 void wxComboBox::Delete(int n
)
586 HIComboBoxRemoveItemAtIndex( (HIViewRef
) m_macControl
, (CFIndex
)n
);
588 // force client object deletion
589 if( HasClientObjectData() )
590 SetClientObject( n
, NULL
);
591 m_choice
->Delete( n
);
595 void wxComboBox::Clear()
599 for ( CFIndex i
= GetCount() - 1 ; i
>= 0 ; ++ i
)
600 verify_noerr( HIComboBoxRemoveItemAtIndex( (HIViewRef
) m_macControl
, i
) );
601 wxMacCFStringHolder
cf(wxEmptyString
,m_font
.GetEncoding()) ;
602 CFStringRef cfr
= cf
;
603 SetControlData((ControlRef
) m_macControl
,kHIComboBoxEditTextPart
,kControlEditTextCFStringTag
,
604 sizeof(CFStringRef
),(Ptr
) &cfr
);
610 int wxComboBox::GetSelection() const
613 return FindString( GetStringSelection() ) ;
615 return m_choice
->GetSelection();
619 void wxComboBox::SetSelection(int n
)
622 SetControl32BitValue( (ControlRef
) m_macControl
, n
+ 1 ) ;
624 m_choice
->SetSelection( n
);
626 if ( m_text
!= NULL
)
628 m_text
->SetValue( GetString( n
) );
633 int wxComboBox::FindString(const wxString
& s
) const
636 for( int i
= 0 ; i
< GetCount() ; i
++ )
638 if ( GetString( i
).IsSameAs(s
, FALSE
) )
643 return m_choice
->FindString( s
);
647 wxString
wxComboBox::GetString(int n
) const
650 CFStringRef itemText
;
651 HIComboBoxCopyTextItemAtIndex( (HIViewRef
) m_macControl
, (CFIndex
)n
, &itemText
);
652 return wxMacCFStringHolder(itemText
).AsString();
654 return m_choice
->GetString( n
);
658 wxString
wxComboBox::GetStringSelection() const
662 verify_noerr(GetControlData((ControlRef
) m_macControl
,kHIComboBoxEditTextPart
,kControlEditTextCFStringTag
,
663 sizeof(CFStringRef
),(Ptr
) &cfr
,NULL
));
664 // takes of release responsibility
665 wxMacCFStringHolder
cf( cfr
) ;
666 return cf
.AsString() ;
668 int sel
= GetSelection ();
670 return wxString(this->GetString (sel
));
672 return wxEmptyString
;
676 bool wxComboBox::SetStringSelection(const wxString
& sel
)
678 int s
= FindString (sel
);
688 void wxComboBox::SetString(int n
, const wxString
& s
)
691 verify_noerr ( HIComboBoxInsertTextItemAtIndex( (HIViewRef
) m_macControl
, (CFIndex
) n
,
692 wxMacCFStringHolder(s
, m_font
.GetEncoding()) ) );
693 verify_noerr ( HIComboBoxRemoveItemAtIndex( (HIViewRef
) m_macControl
, (CFIndex
) n
+ 1 ) );
695 m_choice
->SetString( n
, s
) ;
700 wxInt32
wxComboBox::MacControlHit(WXEVENTHANDLERREF
WXUNUSED(handler
) , WXEVENTREF
WXUNUSED(event
) )
702 wxCommandEvent
event(wxEVT_COMMAND_COMBOBOX_SELECTED
, m_windowId
);
703 event
.SetInt(GetSelection());
704 event
.SetEventObject(this);
705 event
.SetString(GetStringSelection());
706 ProcessCommand(event
);