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