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