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