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