]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/combobox.cpp
*** empty log message ***
[wxWidgets.git] / src / mac / carbon / combobox.cpp
CommitLineData
e9576ca5
SC
1/////////////////////////////////////////////////////////////////////////////
2// Name: combobox.cpp
3// Purpose: wxComboBox class
a31a5f85 4// Author: Stefan Csomor
e9576ca5 5// Modified by:
a31a5f85 6// Created: 1998-01-01
e9576ca5 7// RCS-ID: $Id$
a31a5f85 8// Copyright: (c) Stefan Csomor
65571936 9// Licence: wxWindows licence
e9576ca5
SC
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "combobox.h"
14#endif
15
16#include "wx/combobox.h"
b5a8b32f 17#include "wx/button.h"
03e11df5 18#include "wx/menu.h"
519cb848 19#include "wx/mac/uma.h"
e9576ca5 20
2f1ae414 21#if !USE_SHARED_LIBRARY
e9576ca5 22IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
2f1ae414 23#endif
e9576ca5 24
12f31626
SC
25// composite combobox implementation by Dan "Bud" Keith bud@otsys.com
26
519cb848 27
0e03d1fa 28static int nextPopUpMenuId = 1000 ;
892e461e
SC
29MenuHandle NewUniqueMenu()
30{
31 MenuHandle handle = NewMenu( nextPopUpMenuId , "\pMenu" ) ;
32 nextPopUpMenuId++ ;
33 return handle ;
34}
519cb848 35
12f31626
SC
36
37// ----------------------------------------------------------------------------
38// constants
39// ----------------------------------------------------------------------------
40
41// the margin between the text control and the choice
6097743a 42#if TARGET_API_MAC_OSX
f26ca7f8
KO
43// margin should be bigger on OS X due to blue highlight
44// around text control.
b5267123 45static const wxCoord MARGIN = 4;
788e118f
SC
46// this is the border a focus rect on OSX is needing
47static const int TEXTFOCUSBORDER = 3 ;
6097743a 48#else
f26ca7f8 49static const wxCoord MARGIN = 2;
788e118f 50static const int TEXTFOCUSBORDER = 0 ;
6097743a 51#endif
12f31626
SC
52static const int POPUPHEIGHT = 23;
53
54
55// ----------------------------------------------------------------------------
56// wxComboBoxText: text control forwards events to combobox
57// ----------------------------------------------------------------------------
58
59class wxComboBoxText : public wxTextCtrl
60{
61public:
62 wxComboBoxText( wxComboBox * cb )
327788ac 63 : wxTextCtrl( cb , 1 )
12f31626
SC
64 {
65 m_cb = cb;
66 }
67
68protected:
8095ef23 69 void OnChar( wxKeyEvent& event )
12f31626 70 {
645b5bd6
JS
71 // Allows processing the tab key to go to the next control
72 if (event.GetKeyCode() == WXK_TAB)
73 {
74 wxNavigationKeyEvent NavEvent;
75 NavEvent.SetEventObject(this);
76 NavEvent.SetDirection(true);
77 NavEvent.SetWindowChange(false);
78
79 // Get the parent of the combo and have it process the navigation?
80 if (m_cb->GetParent()->GetEventHandler()->ProcessEvent(NavEvent))
81 return;
82 }
eb22f2a6 83 if ( event.GetKeyCode() == WXK_RETURN )
8095ef23 84 {
645b5bd6
JS
85 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_cb->GetId());
86 event.SetString( GetValue() );
87 event.SetInt( m_cb->GetSelection() );
88 event.SetEventObject( m_cb );
8095ef23 89
645b5bd6
JS
90 // This will invoke the dialog default action, such
91 // as the clicking the default button.
8095ef23 92
645b5bd6
JS
93 if (!m_cb->GetEventHandler()->ProcessEvent( event ))
94 {
8095ef23
SC
95 wxWindow *parent = GetParent();
96 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
e40298d5 97 parent = parent->GetParent() ;
8095ef23
SC
98 }
99 if ( parent && parent->GetDefaultItem() )
100 {
101 wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
102 wxButton);
103 if ( def && def->IsEnabled() )
104 {
105 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
106 event.SetEventObject(def);
107 def->Command(event);
8095ef23
SC
108 }
109 }
110
111 return;
112 }
113 }
22a70443 114
12f31626
SC
115 event.Skip();
116 }
117
645b5bd6
JS
118 // Use the KeyUp as a naive approximation for TEXT_UPDATED, even though it is somewhat delayed
119 // but this is less complicated than dealing with idle-ness, and is much better than nothing
120 void OnKeyUp( wxKeyEvent& event )
121 {
122 if ( event.GetKeyCode() != WXK_RETURN )
123 {
124 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_cb->GetId());
125 event.SetString( GetValue() );
126 event.SetEventObject( m_cb );
127 m_cb->GetEventHandler()->ProcessEvent(event);
128 }
129 }
12f31626
SC
130private:
131 wxComboBox *m_cb;
132
133 DECLARE_EVENT_TABLE()
134};
135
136BEGIN_EVENT_TABLE(wxComboBoxText, wxTextCtrl)
8095ef23 137 EVT_CHAR( wxComboBoxText::OnChar)
645b5bd6 138 EVT_KEY_UP( wxComboBoxText::OnKeyUp)
12f31626
SC
139END_EVENT_TABLE()
140
141class wxComboBoxChoice : public wxChoice
142{
143public:
144 wxComboBoxChoice(wxComboBox *cb, int style)
327788ac 145 : wxChoice( cb , 1 )
12f31626
SC
146 {
147 m_cb = cb;
148 }
ff6871ef
SC
149 int GetPopupWidth() const
150 {
151 switch ( GetWindowVariant() )
152 {
153 case wxWINDOW_VARIANT_NORMAL :
154 case wxWINDOW_VARIANT_LARGE :
155 return 24 ;
156 default :
157 return 21 ;
158 }
159 }
12f31626
SC
160
161protected:
162 void OnChoice( wxCommandEvent& e )
163 {
164 wxString s = e.GetString();
165
166 m_cb->DelegateChoice( s );
8095ef23
SC
167 wxCommandEvent event2(wxEVT_COMMAND_COMBOBOX_SELECTED, m_cb->GetId() );
168 event2.SetInt(m_cb->GetSelection());
169 event2.SetEventObject(m_cb);
170 event2.SetString(m_cb->GetStringSelection());
171 m_cb->ProcessCommand(event2);
645b5bd6
JS
172
173 // For consistency with MSW and GTK, also send a text updated event
174 // After all, the text is updated when a selection is made
175 wxCommandEvent TextEvent( wxEVT_COMMAND_TEXT_UPDATED, m_cb->GetId() );
176 TextEvent.SetString( m_cb->GetStringSelection() );
177 TextEvent.SetEventObject( m_cb );
178 m_cb->ProcessCommand( TextEvent );
12f31626 179 }
6097743a
SC
180 virtual wxSize DoGetBestSize() const
181 {
182 wxSize sz = wxChoice::DoGetBestSize() ;
d0770e4a 183 if (! m_cb->HasFlag(wxCB_READONLY) )
ff6871ef 184 sz.x = GetPopupWidth() ;
6097743a
SC
185 return sz ;
186 }
12f31626
SC
187
188private:
189 wxComboBox *m_cb;
190
191 DECLARE_EVENT_TABLE()
192};
193
194BEGIN_EVENT_TABLE(wxComboBoxChoice, wxChoice)
195 EVT_CHOICE(-1, wxComboBoxChoice::OnChoice)
196END_EVENT_TABLE()
197
12f31626
SC
198wxComboBox::~wxComboBox()
199{
e94e2e95
MB
200 // delete client objects
201 FreeData();
202
203 // delete the controls now, don't leave them alive even though they would
12f31626
SC
204 // still be eventually deleted by our parent - but it will be too late, the
205 // user code expects them to be gone now
f5bb2251
GD
206 if (m_text != NULL) {
207 delete m_text;
208 m_text = NULL;
209 }
210 if (m_choice != NULL) {
211 delete m_choice;
212 m_choice = NULL;
213 }
12f31626
SC
214}
215
216
217// ----------------------------------------------------------------------------
218// geometry
219// ----------------------------------------------------------------------------
220
221wxSize wxComboBox::DoGetBestSize() const
222{
88db1d64 223 if (!m_choice && !m_text)
1deb64c0 224 return GetSize();
12f31626
SC
225 wxSize size = m_choice->GetBestSize();
226
d99937cd 227 if ( m_text != NULL )
12f31626
SC
228 {
229 wxSize sizeText = m_text->GetBestSize();
f26ca7f8
KO
230 if (sizeText.y > size.y)
231 size.y = sizeText.y;
ff6871ef 232 size.x = m_choice->GetPopupWidth() + sizeText.x + MARGIN;
788e118f
SC
233 size.x += TEXTFOCUSBORDER ;
234 size.y += 2 * TEXTFOCUSBORDER ;
12f31626 235 }
ff6871ef
SC
236 else
237 {
238 // clipping is too tight
239 size.y += 1 ;
240 }
12f31626
SC
241 return size;
242}
243
ff6871ef
SC
244void wxComboBox::DoMoveWindow(int x, int y, int width, int height)
245{
788e118f
SC
246 wxControl::DoMoveWindow(x, y, width , height );
247
d99937cd 248 if ( m_text == NULL )
12f31626 249 {
facd6764
SC
250 // we might not be fully constructed yet, therefore watch out...
251 if ( m_choice )
252 m_choice->SetSize(0, 0 , width, -1);
12f31626
SC
253 }
254 else
255 {
ff6871ef 256 wxCoord wText = width - m_choice->GetPopupWidth() - MARGIN;
788e118f 257 m_text->SetSize(TEXTFOCUSBORDER, TEXTFOCUSBORDER, wText, -1 );
ff6871ef
SC
258 // put it at an inset of 1 to have outer area shadows drawn as well
259 m_choice->SetSize(TEXTFOCUSBORDER + wText + MARGIN - 1 , TEXTFOCUSBORDER, m_choice->GetPopupWidth() , -1);
12f31626
SC
260 }
261}
262
263
264
265// ----------------------------------------------------------------------------
266// operations forwarded to the subcontrols
267// ----------------------------------------------------------------------------
268
269bool wxComboBox::Enable(bool enable)
270{
271 if ( !wxControl::Enable(enable) )
272 return FALSE;
273
12f31626
SC
274 return TRUE;
275}
276
277bool wxComboBox::Show(bool show)
278{
279 if ( !wxControl::Show(show) )
280 return FALSE;
281
12f31626
SC
282 return TRUE;
283}
284
d99937cd
GD
285void wxComboBox::SetFocus()
286{
287 if ( m_text != NULL) {
288 m_text->SetFocus();
289 }
290}
465605e0 291
12f31626 292
d99937cd
GD
293void wxComboBox::DelegateTextChanged( const wxString& value )
294{
8095ef23 295 SetStringSelection( value );
12f31626
SC
296}
297
298
299void wxComboBox::DelegateChoice( const wxString& value )
300{
301 SetStringSelection( value );
302}
303
304
584ad2a3
MB
305bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
306 const wxString& value,
307 const wxPoint& pos,
308 const wxSize& size,
309 const wxArrayString& choices,
310 long style,
311 const wxValidator& validator,
312 const wxString& name)
313{
314 wxCArrayString chs( choices );
315
316 return Create( parent, id, value, pos, size, chs.GetCount(),
317 chs.GetStrings(), style, validator, name );
318}
319
320
e9576ca5
SC
321bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
322 const wxString& value,
323 const wxPoint& pos,
324 const wxSize& size,
465605e0
RR
325 int n, const wxString choices[],
326 long style,
e9576ca5
SC
327 const wxValidator& validator,
328 const wxString& name)
329{
327788ac 330 if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style ,
12f31626
SC
331 wxDefaultValidator, name) )
332 {
333 return FALSE;
334 }
335
327788ac 336 m_choice = new wxComboBoxChoice(this, style );
12f31626
SC
337 wxSize csize = size;
338 if ( style & wxCB_READONLY )
339 {
d99937cd 340 m_text = NULL;
12f31626
SC
341 }
342 else
343 {
344 m_text = new wxComboBoxText(this);
788e118f
SC
345 if ( size.y == -1 )
346 {
347 csize.y = m_text->GetSize().y ;
348 csize.y += 2 * TEXTFOCUSBORDER ;
12f31626
SC
349 }
350 }
351
352 DoSetSize(pos.x, pos.y, csize.x, csize.y);
327788ac 353
12f31626
SC
354 for ( int i = 0 ; i < n ; i++ )
355 {
465605e0 356 m_choice->DoAppend( choices[ i ] );
12f31626
SC
357 }
358
88db1d64 359 SetBestSize(size); // Needed because it is a wxControlWithItems
d3b5db4b 360
12f31626 361 return TRUE;
e9576ca5
SC
362}
363
364wxString wxComboBox::GetValue() const
365{
12f31626
SC
366 wxString result;
367
d99937cd 368 if ( m_text == NULL )
12f31626
SC
369 {
370 result = m_choice->GetString( m_choice->GetSelection() );
371 }
372 else
373 {
374 result = m_text->GetValue();
375 }
376
377 return result;
e9576ca5
SC
378}
379
46cc7c4e
SC
380int wxComboBox::GetCount() const
381{
382 return m_choice->GetCount() ;
383}
384
e9576ca5
SC
385void wxComboBox::SetValue(const wxString& value)
386{
30a936ee
SC
387 if ( HasFlag(wxCB_READONLY) )
388 SetStringSelection( value ) ;
389 else
390 m_text->SetValue( value );
e9576ca5
SC
391}
392
393// Clipboard operations
394void wxComboBox::Copy()
395{
d99937cd 396 if ( m_text != NULL )
12f31626
SC
397 {
398 m_text->Copy();
399 }
e9576ca5
SC
400}
401
402void wxComboBox::Cut()
403{
d99937cd 404 if ( m_text != NULL )
12f31626
SC
405 {
406 m_text->Cut();
407 }
e9576ca5
SC
408}
409
410void wxComboBox::Paste()
411{
d99937cd 412 if ( m_text != NULL )
12f31626
SC
413 {
414 m_text->Paste();
415 }
e9576ca5
SC
416}
417
418void wxComboBox::SetEditable(bool editable)
419{
d99937cd 420 if ( ( m_text == NULL ) && editable )
12f31626
SC
421 {
422 m_text = new wxComboBoxText( this );
423 }
d99937cd 424 else if ( ( m_text != NULL ) && !editable )
12f31626
SC
425 {
426 delete m_text;
d99937cd 427 m_text = NULL;
12f31626
SC
428 }
429
430 int currentX, currentY;
431 GetPosition( &currentX, &currentY );
432
433 int currentW, currentH;
434 GetSize( &currentW, &currentH );
435
436 DoMoveWindow( currentX, currentY, currentW, currentH );
e9576ca5
SC
437}
438
439void wxComboBox::SetInsertionPoint(long pos)
440{
441 // TODO
442}
443
444void wxComboBox::SetInsertionPointEnd()
445{
446 // TODO
447}
448
449long wxComboBox::GetInsertionPoint() const
450{
451 // TODO
452 return 0;
453}
454
455long wxComboBox::GetLastPosition() const
456{
457 // TODO
458 return 0;
459}
460
461void wxComboBox::Replace(long from, long to, const wxString& value)
462{
463 // TODO
464}
465
466void wxComboBox::Remove(long from, long to)
467{
468 // TODO
469}
470
471void wxComboBox::SetSelection(long from, long to)
472{
473 // TODO
474}
475
e71a0aa9 476int wxComboBox::DoAppend(const wxString& item)
e9576ca5 477{
e71a0aa9
SC
478 return m_choice->DoAppend( item ) ;
479}
480
481int wxComboBox::DoInsert(const wxString& item, int pos)
482{
483 return m_choice->DoInsert( item , pos ) ;
484}
485
486void wxComboBox::DoSetItemClientData(int n, void* clientData)
487{
f148f2ba 488 return m_choice->DoSetItemClientData( n , clientData ) ;
e71a0aa9
SC
489}
490
491void* wxComboBox::DoGetItemClientData(int n) const
492{
f148f2ba 493 return m_choice->DoGetItemClientData( n ) ;
e71a0aa9 494}
22a70443 495
e71a0aa9
SC
496void wxComboBox::DoSetItemClientObject(int n, wxClientData* clientData)
497{
f148f2ba 498 return m_choice->DoSetItemClientObject( n , clientData ) ;
e71a0aa9
SC
499}
500
501wxClientData* wxComboBox::DoGetItemClientObject(int n) const
502{
f148f2ba
MB
503 return m_choice->DoGetItemClientObject( n ) ;
504}
505
506void wxComboBox::FreeData()
507{
508 if ( HasClientObjectData() )
509 {
510 size_t count = GetCount();
511 for ( size_t n = 0; n < count; n++ )
512 {
513 SetClientObject( n, NULL );
514 }
515 }
e9576ca5
SC
516}
517
518void wxComboBox::Delete(int n)
519{
f148f2ba
MB
520 // force client object deletion
521 if( HasClientObjectData() )
522 SetClientObject( n, NULL );
12f31626 523 m_choice->Delete( n );
e9576ca5
SC
524}
525
526void wxComboBox::Clear()
527{
f148f2ba 528 FreeData();
12f31626 529 m_choice->Clear();
e9576ca5
SC
530}
531
532int wxComboBox::GetSelection() const
533{
12f31626 534 return m_choice->GetSelection();
e9576ca5
SC
535}
536
537void wxComboBox::SetSelection(int n)
538{
12f31626
SC
539 m_choice->SetSelection( n );
540
d99937cd 541 if ( m_text != NULL )
12f31626
SC
542 {
543 m_text->SetValue( GetString( n ) );
544 }
e9576ca5
SC
545}
546
547int wxComboBox::FindString(const wxString& s) const
548{
12f31626 549 return m_choice->FindString( s );
e9576ca5
SC
550}
551
552wxString wxComboBox::GetString(int n) const
553{
12f31626 554 return m_choice->GetString( n );
e9576ca5
SC
555}
556
557wxString wxComboBox::GetStringSelection() const
558{
519cb848
SC
559 int sel = GetSelection ();
560 if (sel > -1)
561 return wxString(this->GetString (sel));
562 else
427ff662 563 return wxEmptyString;
e9576ca5
SC
564}
565
566bool wxComboBox::SetStringSelection(const wxString& sel)
567{
519cb848
SC
568 int s = FindString (sel);
569 if (s > -1)
570 {
571 SetSelection (s);
572 return TRUE;
573 }
574 else
575 return FALSE;
576}
577
e71a0aa9
SC
578void wxComboBox::SetString(int n, const wxString& s)
579{
580 m_choice->SetString( n , s ) ;
581}
582
583
4c37f124 584wxInt32 wxComboBox::MacControlHit(WXEVENTHANDLERREF WXUNUSED(handler) , WXEVENTREF WXUNUSED(event) )
519cb848 585{
645b5bd6 586 /* For consistency with other platforms, clicking in the text area does not constitute a selection
519cb848 587 wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, m_windowId );
465605e0 588 event.SetInt(GetSelection());
519cb848 589 event.SetEventObject(this);
0a67a93b 590 event.SetString(GetStringSelection());
12fce8fb
RN
591 ProcessCommand(event);*/
592 return noErr ;
e9576ca5 593}
519cb848 594