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