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