]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/combobox.cpp
translating background style BG_PAINT into opaqueness for speed-up of OS redraws...
[wxWidgets.git] / src / osx / carbon / combobox.cpp
CommitLineData
489468fe 1/////////////////////////////////////////////////////////////////////////////
524c47aa 2// Name: src/osx/carbon/combobox.cpp
489468fe
SC
3// Purpose: wxComboBox class
4// Author: Stefan Csomor, Dan "Bud" Keith (composite combobox)
5// Modified by:
6// Created: 1998-01-01
7// RCS-ID: $Id$
8// Copyright: (c) Stefan Csomor
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
c84030e0 14#if wxUSE_COMBOBOX && wxOSX_USE_CARBON
489468fe
SC
15
16#include "wx/combobox.h"
17
18#ifndef WX_PRECOMP
19 #include "wx/button.h"
20 #include "wx/menu.h"
21 #include "wx/containr.h"
22 #include "wx/toplevel.h"
23 #include "wx/textctrl.h"
24#endif
25
524c47aa 26#include "wx/osx/private.h"
489468fe
SC
27
28IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
29
30WX_DELEGATE_TO_CONTROL_CONTAINER(wxComboBox, wxControl)
31
32BEGIN_EVENT_TABLE(wxComboBox, wxControl)
33 WX_EVENT_TABLE_CONTROL_CONTAINER(wxComboBox)
34END_EVENT_TABLE()
35
36
489468fe
SC
37// ----------------------------------------------------------------------------
38// constants
39// ----------------------------------------------------------------------------
40
41// the margin between the text control and the choice
42// margin should be bigger on OS X due to blue highlight
43// around text control.
44static const wxCoord MARGIN = 4;
45// this is the border a focus rect on OSX is needing
46static const int TEXTFOCUSBORDER = 3 ;
47
48
49// ----------------------------------------------------------------------------
50// wxComboBoxText: text control forwards events to combobox
51// ----------------------------------------------------------------------------
52
53class wxComboBoxText : public wxTextCtrl
54{
55public:
56 wxComboBoxText( wxComboBox * cb )
57 : wxTextCtrl( cb , 1 )
58 {
59 m_cb = cb;
489468fe
SC
60 }
61
62protected:
63 void OnChar( wxKeyEvent& event )
64 {
65 // Allows processing the tab key to go to the next control
66 if (event.GetKeyCode() == WXK_TAB)
67 {
68 wxNavigationKeyEvent NavEvent;
69 NavEvent.SetEventObject(this);
70 NavEvent.SetDirection(true);
71 NavEvent.SetWindowChange(false);
72
73 // Get the parent of the combo and have it process the navigation?
74 if (m_cb->GetParent()->HandleWindowEvent(NavEvent))
75 return;
76 }
77
78 // send the event to the combobox class in case the user has bound EVT_CHAR
79 wxKeyEvent kevt(event);
80 kevt.SetEventObject(m_cb);
81 if (m_cb->HandleWindowEvent(kevt))
82 // If the event was handled and not skipped then we're done
83 return;
84
85 if ( event.GetKeyCode() == WXK_RETURN )
86 {
87 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_cb->GetId());
88 event.SetString( GetValue() );
89 event.SetInt( m_cb->GetSelection() );
90 event.SetEventObject( m_cb );
91
92 // This will invoke the dialog default action,
93 // such as the clicking the default button.
94 if (!m_cb->HandleWindowEvent( event ))
95 {
96 wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
97 if ( tlw && tlw->GetDefaultItem() )
98 {
99 wxButton *def = wxDynamicCast(tlw->GetDefaultItem(), wxButton);
100 if ( def && def->IsEnabled() )
101 {
102 wxCommandEvent event( wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
103 event.SetEventObject(def);
104 def->Command(event);
105 }
106 }
107
108 return;
109 }
110 }
111
112 event.Skip();
113 }
114
115 void OnKeyUp( wxKeyEvent& event )
116 {
117 event.SetEventObject(m_cb);
118 event.SetId(m_cb->GetId());
119 if (! m_cb->HandleWindowEvent(event))
120 event.Skip();
121 }
122
123 void OnKeyDown( wxKeyEvent& event )
124 {
125 event.SetEventObject(m_cb);
126 event.SetId(m_cb->GetId());
127 if (! m_cb->HandleWindowEvent(event))
128 event.Skip();
129 }
130
131 void OnText( wxCommandEvent& event )
132 {
133 event.SetEventObject(m_cb);
134 event.SetId(m_cb->GetId());
135 if (! m_cb->HandleWindowEvent(event))
136 event.Skip();
137 }
138
9044b125
SC
139 void OnFocus( wxFocusEvent& event )
140 {
141 // in case the textcontrol gets the focus we propagate
142 // it to the parent's handlers.
143 wxFocusEvent evt2(event.GetEventType(),m_cb->GetId());
144 evt2.SetEventObject(m_cb);
145 m_cb->GetEventHandler()->ProcessEvent(evt2);
146
147 event.Skip();
148 }
03647350 149
489468fe
SC
150private:
151 wxComboBox *m_cb;
152
153 DECLARE_EVENT_TABLE()
154};
155
156BEGIN_EVENT_TABLE(wxComboBoxText, wxTextCtrl)
157 EVT_KEY_DOWN(wxComboBoxText::OnKeyDown)
158 EVT_CHAR(wxComboBoxText::OnChar)
159 EVT_KEY_UP(wxComboBoxText::OnKeyUp)
9044b125
SC
160 EVT_SET_FOCUS(wxComboBoxText::OnFocus)
161 EVT_KILL_FOCUS(wxComboBoxText::OnFocus)
489468fe
SC
162 EVT_TEXT(wxID_ANY, wxComboBoxText::OnText)
163END_EVENT_TABLE()
164
165class wxComboBoxChoice : public wxChoice
166{
167public:
168 wxComboBoxChoice( wxComboBox *cb, int style )
169 : wxChoice( cb , 1 , wxDefaultPosition , wxDefaultSize , 0 , NULL , style & (wxCB_SORT) )
170 {
171 m_cb = cb;
172 }
173
174 int GetPopupWidth() const
175 {
176 switch ( GetWindowVariant() )
177 {
178 case wxWINDOW_VARIANT_NORMAL :
179 case wxWINDOW_VARIANT_LARGE :
180 return 24 ;
181
182 default :
183 return 21 ;
184 }
185 }
186
187protected:
188 void OnChoice( wxCommandEvent& e )
189 {
190 wxString s = e.GetString();
191
192 m_cb->DelegateChoice( s );
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);
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 );
205 }
206
207 virtual wxSize DoGetBestSize() const
208 {
209 wxSize sz = wxChoice::DoGetBestSize() ;
210 if (! m_cb->HasFlag(wxCB_READONLY) )
211 sz.x = GetPopupWidth() ;
212
213 return sz ;
214 }
215
216private:
217 wxComboBox *m_cb;
218
219 friend class wxComboBox;
220
221 DECLARE_EVENT_TABLE()
222};
223
224BEGIN_EVENT_TABLE(wxComboBoxChoice, wxChoice)
225 EVT_CHOICE(wxID_ANY, wxComboBoxChoice::OnChoice)
226END_EVENT_TABLE()
227
228wxComboBox::~wxComboBox()
229{
230 // delete the controls now, don't leave them alive even though they would
231 // still be eventually deleted by our parent - but it will be too late, the
232 // user code expects them to be gone now
233 if (m_text != NULL)
234 {
235 delete m_text;
236 m_text = NULL;
237 }
238
239 if (m_choice != NULL)
240 {
241 delete m_choice;
242 m_choice = NULL;
243 }
244}
245
246// ----------------------------------------------------------------------------
247// geometry
248// ----------------------------------------------------------------------------
249
250wxSize wxComboBox::DoGetBestSize() const
251{
252 if (!m_choice && !m_text)
253 return GetSize();
254
255 wxSize size = m_choice->GetBestSize();
256
257 if ( m_text != NULL )
258 {
259 wxSize sizeText = m_text->GetBestSize();
d33e45f1
SC
260 if (sizeText.y + 2 * TEXTFOCUSBORDER > size.y)
261 size.y = sizeText.y + 2 * TEXTFOCUSBORDER;
489468fe
SC
262
263 size.x = m_choice->GetPopupWidth() + sizeText.x + MARGIN;
264 size.x += TEXTFOCUSBORDER ;
489468fe
SC
265 }
266 else
267 {
268 // clipping is too tight
269 size.y += 1 ;
270 }
271
272 return size;
273}
274
275void wxComboBox::DoMoveWindow(int x, int y, int width, int height)
276{
277 wxControl::DoMoveWindow( x, y, width , height );
278
279 if ( m_text == NULL )
280 {
281 // we might not be fully constructed yet, therefore watch out...
282 if ( m_choice )
283 m_choice->SetSize(0, 0 , width, -1);
284 }
285 else
286 {
287 wxCoord wText = width - m_choice->GetPopupWidth() - MARGIN;
288 m_text->SetSize(TEXTFOCUSBORDER, TEXTFOCUSBORDER, wText, -1);
d33e45f1
SC
289 wxSize tSize = m_text->GetSize();
290 wxSize cSize = m_choice->GetSize();
03647350 291
d33e45f1 292 int yOffset = ( tSize.y + 2 * TEXTFOCUSBORDER - cSize.y ) / 2;
489468fe
SC
293
294 // put it at an inset of 1 to have outer area shadows drawn as well
d33e45f1 295 m_choice->SetSize(TEXTFOCUSBORDER + wText + MARGIN - 1 , yOffset, m_choice->GetPopupWidth() , -1);
489468fe
SC
296 }
297}
298
299// ----------------------------------------------------------------------------
300// operations forwarded to the subcontrols
301// ----------------------------------------------------------------------------
302
303bool wxComboBox::Enable(bool enable)
304{
305 if ( !wxControl::Enable(enable) )
306 return false;
307
308 if (m_text)
309 m_text->Enable(enable);
310
311 return true;
312}
313
314bool wxComboBox::Show(bool show)
315{
316 if ( !wxControl::Show(show) )
317 return false;
318
319 return true;
320}
321
322void wxComboBox::DelegateTextChanged( const wxString& value )
323{
324 SetStringSelection( value );
325}
326
327void wxComboBox::DelegateChoice( const wxString& value )
328{
329 SetStringSelection( value );
330}
331
332void wxComboBox::Init()
333{
334 WX_INIT_CONTROL_CONTAINER();
335}
336
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)
346{
347 if ( !Create( parent, id, value, pos, size, 0, NULL,
348 style, validator, name ) )
349 return false;
350
351 Append(choices);
352
353 return true;
354}
355
356bool wxComboBox::Create(wxWindow *parent,
357 wxWindowID id,
358 const wxString& value,
359 const wxPoint& pos,
360 const wxSize& size,
361 int n,
362 const wxString choices[],
363 long style,
364 const wxValidator& validator,
365 const wxString& name)
366{
367 if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style ,
368 validator, name) )
369 {
370 return false;
371 }
372
373 wxSize csize = size;
374 if ( style & wxCB_READONLY )
375 {
376 m_text = NULL;
377 }
378 else
379 {
380 m_text = new wxComboBoxText(this);
381 if ( size.y == -1 )
382 {
383 csize.y = m_text->GetSize().y ;
384 csize.y += 2 * TEXTFOCUSBORDER ;
385 }
386 }
387 m_choice = new wxComboBoxChoice(this, style );
388
389 DoSetSize(pos.x, pos.y, csize.x, csize.y);
390
391 Append( n, choices );
392
393 // Needed because it is a wxControlWithItems
394 SetInitialSize(size);
395 SetStringSelection(value);
396
397 return true;
398}
399
d9d551f6 400void wxComboBox::EnableTextChangedEvents(bool enable)
03647350 401{
d9d551f6
SC
402 if ( m_text )
403 m_text->ForwardEnableTextChangedEvents(enable);
404}
405
00c89b22
VZ
406wxString wxComboBox::DoGetValue() const
407{
408 wxCHECK_MSG( m_text, wxString(), "can't be called for read-only combobox" );
409
410 return m_text->GetValue();
411}
412
489468fe
SC
413wxString wxComboBox::GetValue() const
414{
415 wxString result;
416
417 if ( m_text == NULL )
418 result = m_choice->GetString( m_choice->GetSelection() );
419 else
420 result = m_text->GetValue();
421
422 return result;
423}
424
425unsigned int wxComboBox::GetCount() const
426{
427 return m_choice->GetCount() ;
428}
429
430void wxComboBox::SetValue(const wxString& value)
431{
432 if ( HasFlag(wxCB_READONLY) )
433 SetStringSelection( value ) ;
434 else
435 m_text->SetValue( value );
436}
437
438void wxComboBox::WriteText(const wxString& text)
439{
440 m_text->WriteText(text);
441}
442
443void wxComboBox::GetSelection(long *from, long *to) const
444{
445 m_text->GetSelection(from, to);
446}
447
448// Clipboard operations
449
450void wxComboBox::Copy()
451{
452 if ( m_text != NULL )
453 m_text->Copy();
454}
455
456void wxComboBox::Cut()
457{
458 if ( m_text != NULL )
459 m_text->Cut();
460}
461
462void wxComboBox::Paste()
463{
464 if ( m_text != NULL )
465 m_text->Paste();
466}
467
468void wxComboBox::SetEditable(bool editable)
469{
470 if ( ( m_text == NULL ) && editable )
471 {
472 m_text = new wxComboBoxText( this );
473 }
474 else if ( ( m_text != NULL ) && !editable )
475 {
476 delete m_text;
477 m_text = NULL;
478 }
479
480 int currentX, currentY;
481 GetPosition( &currentX, &currentY );
482
483 int currentW, currentH;
484 GetSize( &currentW, &currentH );
485
486 DoMoveWindow( currentX, currentY, currentW, currentH );
487}
488
489void wxComboBox::SetInsertionPoint(long pos)
490{
491 if ( m_text )
492 m_text->SetInsertionPoint(pos);
493}
494
495void wxComboBox::SetInsertionPointEnd()
496{
497 if ( m_text )
498 m_text->SetInsertionPointEnd();
499}
500
501long wxComboBox::GetInsertionPoint() const
502{
503 if ( m_text )
504 return m_text->GetInsertionPoint();
505 return 0;
506}
507
508wxTextPos wxComboBox::GetLastPosition() const
509{
510 if ( m_text )
511 return m_text->GetLastPosition();
512 return 0;
513}
514
515void wxComboBox::Replace(long from, long to, const wxString& value)
516{
517 if ( m_text )
518 m_text->Replace(from,to,value);
519}
520
521void wxComboBox::Remove(long from, long to)
522{
523 if ( m_text )
524 m_text->Remove(from,to);
525}
526
527void wxComboBox::SetSelection(long from, long to)
528{
529 if ( m_text )
530 m_text->SetSelection(from,to);
531}
532
533int wxComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
534 unsigned int pos,
535 void **clientData,
536 wxClientDataType type)
537{
538 return m_choice->DoInsertItems(items, pos, clientData, type);
539}
540
541void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
542{
543 return m_choice->DoSetItemClientData( n , clientData ) ;
544}
545
546void* wxComboBox::DoGetItemClientData(unsigned int n) const
547{
548 return m_choice->DoGetItemClientData( n ) ;
549}
550
551wxClientDataType wxComboBox::GetClientDataType() const
552{
553 return m_choice->GetClientDataType();
554}
555
556void wxComboBox::SetClientDataType(wxClientDataType clientDataItemsType)
557{
558 m_choice->SetClientDataType(clientDataItemsType);
559}
560
561void wxComboBox::DoDeleteOneItem(unsigned int n)
562{
563 m_choice->DoDeleteOneItem( n );
564}
565
566void wxComboBox::DoClear()
567{
568 m_choice->DoClear();
569}
570
571int wxComboBox::GetSelection() const
572{
573 return m_choice->GetSelection();
574}
575
576void wxComboBox::SetSelection(int n)
577{
578 m_choice->SetSelection( n );
579
580 if ( m_text != NULL )
581 m_text->SetValue(n != wxNOT_FOUND ? GetString(n) : wxString(wxEmptyString));
582}
583
584int wxComboBox::FindString(const wxString& s, bool bCase) const
585{
586 return m_choice->FindString( s, bCase );
587}
588
589wxString wxComboBox::GetString(unsigned int n) const
590{
591 return m_choice->GetString( n );
592}
593
594wxString wxComboBox::GetStringSelection() const
595{
596 int sel = GetSelection();
597 if (sel != wxNOT_FOUND)
598 return wxString(this->GetString((unsigned int)sel));
599 else
600 return wxEmptyString;
601}
602
603void wxComboBox::SetString(unsigned int n, const wxString& s)
604{
605 m_choice->SetString( n , s );
606}
607
608bool wxComboBox::IsEditable() const
609{
610 return m_text != NULL && !HasFlag(wxCB_READONLY);
611}
612
613void wxComboBox::Undo()
614{
615 if (m_text != NULL)
616 m_text->Undo();
617}
618
619void wxComboBox::Redo()
620{
621 if (m_text != NULL)
622 m_text->Redo();
623}
624
625void wxComboBox::SelectAll()
626{
627 if (m_text != NULL)
628 m_text->SelectAll();
629}
630
631bool wxComboBox::CanCopy() const
632{
633 if (m_text != NULL)
634 return m_text->CanCopy();
635 else
636 return false;
637}
638
639bool wxComboBox::CanCut() const
640{
641 if (m_text != NULL)
642 return m_text->CanCut();
643 else
644 return false;
645}
646
647bool wxComboBox::CanPaste() const
648{
649 if (m_text != NULL)
650 return m_text->CanPaste();
651 else
652 return false;
653}
654
655bool wxComboBox::CanUndo() const
656{
657 if (m_text != NULL)
658 return m_text->CanUndo();
659 else
660 return false;
661}
662
663bool wxComboBox::CanRedo() const
664{
665 if (m_text != NULL)
666 return m_text->CanRedo();
667 else
668 return false;
669}
670
de0d2095 671bool wxComboBox::OSXHandleClicked( double WXUNUSED(timestampsec) )
489468fe
SC
672{
673/*
674 For consistency with other platforms, clicking in the text area does not constitute a selection
675 wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, m_windowId );
676 event.SetInt(GetSelection());
677 event.SetEventObject(this);
678 event.SetString(GetStringSelection());
679 ProcessCommand(event);
680*/
681
524c47aa 682 return true ;
489468fe
SC
683}
684
c84030e0
KO
685wxTextWidgetImpl* wxComboBox::GetTextPeer() const
686{
687 if (m_text)
688 return m_text->GetTextPeer();
689
690 return NULL;
691}
692
693#endif // wxUSE_COMBOBOX && wxOSX_USE_CARBON