]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/combobox.cpp
DoGetAsBitmap implementation for Cocoa.
[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
14#if wxUSE_COMBOBOX
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;
60 SetTriggerOnSetValue( false );
61 }
62
63protected:
64 void OnChar( wxKeyEvent& event )
65 {
66 // Allows processing the tab key to go to the next control
67 if (event.GetKeyCode() == WXK_TAB)
68 {
69 wxNavigationKeyEvent NavEvent;
70 NavEvent.SetEventObject(this);
71 NavEvent.SetDirection(true);
72 NavEvent.SetWindowChange(false);
73
74 // Get the parent of the combo and have it process the navigation?
75 if (m_cb->GetParent()->HandleWindowEvent(NavEvent))
76 return;
77 }
78
79 // send the event to the combobox class in case the user has bound EVT_CHAR
80 wxKeyEvent kevt(event);
81 kevt.SetEventObject(m_cb);
82 if (m_cb->HandleWindowEvent(kevt))
83 // If the event was handled and not skipped then we're done
84 return;
85
86 if ( event.GetKeyCode() == WXK_RETURN )
87 {
88 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_cb->GetId());
89 event.SetString( GetValue() );
90 event.SetInt( m_cb->GetSelection() );
91 event.SetEventObject( m_cb );
92
93 // This will invoke the dialog default action,
94 // such as the clicking the default button.
95 if (!m_cb->HandleWindowEvent( event ))
96 {
97 wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
98 if ( tlw && tlw->GetDefaultItem() )
99 {
100 wxButton *def = wxDynamicCast(tlw->GetDefaultItem(), wxButton);
101 if ( def && def->IsEnabled() )
102 {
103 wxCommandEvent event( wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
104 event.SetEventObject(def);
105 def->Command(event);
106 }
107 }
108
109 return;
110 }
111 }
112
113 event.Skip();
114 }
115
116 void OnKeyUp( wxKeyEvent& event )
117 {
118 event.SetEventObject(m_cb);
119 event.SetId(m_cb->GetId());
120 if (! m_cb->HandleWindowEvent(event))
121 event.Skip();
122 }
123
124 void OnKeyDown( wxKeyEvent& event )
125 {
126 event.SetEventObject(m_cb);
127 event.SetId(m_cb->GetId());
128 if (! m_cb->HandleWindowEvent(event))
129 event.Skip();
130 }
131
132 void OnText( wxCommandEvent& event )
133 {
134 event.SetEventObject(m_cb);
135 event.SetId(m_cb->GetId());
136 if (! m_cb->HandleWindowEvent(event))
137 event.Skip();
138 }
139
140private:
141 wxComboBox *m_cb;
142
143 DECLARE_EVENT_TABLE()
144};
145
146BEGIN_EVENT_TABLE(wxComboBoxText, wxTextCtrl)
147 EVT_KEY_DOWN(wxComboBoxText::OnKeyDown)
148 EVT_CHAR(wxComboBoxText::OnChar)
149 EVT_KEY_UP(wxComboBoxText::OnKeyUp)
150 EVT_TEXT(wxID_ANY, wxComboBoxText::OnText)
151END_EVENT_TABLE()
152
153class wxComboBoxChoice : public wxChoice
154{
155public:
156 wxComboBoxChoice( wxComboBox *cb, int style )
157 : wxChoice( cb , 1 , wxDefaultPosition , wxDefaultSize , 0 , NULL , style & (wxCB_SORT) )
158 {
159 m_cb = cb;
160 }
161
162 int GetPopupWidth() const
163 {
164 switch ( GetWindowVariant() )
165 {
166 case wxWINDOW_VARIANT_NORMAL :
167 case wxWINDOW_VARIANT_LARGE :
168 return 24 ;
169
170 default :
171 return 21 ;
172 }
173 }
174
175protected:
176 void OnChoice( wxCommandEvent& e )
177 {
178 wxString s = e.GetString();
179
180 m_cb->DelegateChoice( s );
181 wxCommandEvent event2(wxEVT_COMMAND_COMBOBOX_SELECTED, m_cb->GetId() );
182 event2.SetInt(m_cb->GetSelection());
183 event2.SetEventObject(m_cb);
184 event2.SetString(m_cb->GetStringSelection());
185 m_cb->ProcessCommand(event2);
186
187 // For consistency with MSW and GTK, also send a text updated event
188 // After all, the text is updated when a selection is made
189 wxCommandEvent TextEvent( wxEVT_COMMAND_TEXT_UPDATED, m_cb->GetId() );
190 TextEvent.SetString( m_cb->GetStringSelection() );
191 TextEvent.SetEventObject( m_cb );
192 m_cb->ProcessCommand( TextEvent );
193 }
194
195 virtual wxSize DoGetBestSize() const
196 {
197 wxSize sz = wxChoice::DoGetBestSize() ;
198 if (! m_cb->HasFlag(wxCB_READONLY) )
199 sz.x = GetPopupWidth() ;
200
201 return sz ;
202 }
203
204private:
205 wxComboBox *m_cb;
206
207 friend class wxComboBox;
208
209 DECLARE_EVENT_TABLE()
210};
211
212BEGIN_EVENT_TABLE(wxComboBoxChoice, wxChoice)
213 EVT_CHOICE(wxID_ANY, wxComboBoxChoice::OnChoice)
214END_EVENT_TABLE()
215
216wxComboBox::~wxComboBox()
217{
218 // delete the controls now, don't leave them alive even though they would
219 // still be eventually deleted by our parent - but it will be too late, the
220 // user code expects them to be gone now
221 if (m_text != NULL)
222 {
223 delete m_text;
224 m_text = NULL;
225 }
226
227 if (m_choice != NULL)
228 {
229 delete m_choice;
230 m_choice = NULL;
231 }
232}
233
234// ----------------------------------------------------------------------------
235// geometry
236// ----------------------------------------------------------------------------
237
238wxSize wxComboBox::DoGetBestSize() const
239{
240 if (!m_choice && !m_text)
241 return GetSize();
242
243 wxSize size = m_choice->GetBestSize();
244
245 if ( m_text != NULL )
246 {
247 wxSize sizeText = m_text->GetBestSize();
248 if (sizeText.y > size.y)
249 size.y = sizeText.y;
250
251 size.x = m_choice->GetPopupWidth() + sizeText.x + MARGIN;
252 size.x += TEXTFOCUSBORDER ;
253 size.y += 2 * TEXTFOCUSBORDER ;
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);
278
279 // put it at an inset of 1 to have outer area shadows drawn as well
280 m_choice->SetSize(TEXTFOCUSBORDER + wText + MARGIN - 1 , TEXTFOCUSBORDER, m_choice->GetPopupWidth() , -1);
281 }
282}
283
284// ----------------------------------------------------------------------------
285// operations forwarded to the subcontrols
286// ----------------------------------------------------------------------------
287
288bool wxComboBox::Enable(bool enable)
289{
290 if ( !wxControl::Enable(enable) )
291 return false;
292
293 if (m_text)
294 m_text->Enable(enable);
295
296 return true;
297}
298
299bool wxComboBox::Show(bool show)
300{
301 if ( !wxControl::Show(show) )
302 return false;
303
304 return true;
305}
306
307void wxComboBox::DelegateTextChanged( const wxString& value )
308{
309 SetStringSelection( value );
310}
311
312void wxComboBox::DelegateChoice( const wxString& value )
313{
314 SetStringSelection( value );
315}
316
317void wxComboBox::Init()
318{
319 WX_INIT_CONTROL_CONTAINER();
320}
321
322bool wxComboBox::Create(wxWindow *parent,
323 wxWindowID id,
324 const wxString& value,
325 const wxPoint& pos,
326 const wxSize& size,
327 const wxArrayString& choices,
328 long style,
329 const wxValidator& validator,
330 const wxString& name)
331{
332 if ( !Create( parent, id, value, pos, size, 0, NULL,
333 style, validator, name ) )
334 return false;
335
336 Append(choices);
337
338 return true;
339}
340
341bool wxComboBox::Create(wxWindow *parent,
342 wxWindowID id,
343 const wxString& value,
344 const wxPoint& pos,
345 const wxSize& size,
346 int n,
347 const wxString choices[],
348 long style,
349 const wxValidator& validator,
350 const wxString& name)
351{
352 if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style ,
353 validator, name) )
354 {
355 return false;
356 }
357
358 wxSize csize = size;
359 if ( style & wxCB_READONLY )
360 {
361 m_text = NULL;
362 }
363 else
364 {
365 m_text = new wxComboBoxText(this);
366 if ( size.y == -1 )
367 {
368 csize.y = m_text->GetSize().y ;
369 csize.y += 2 * TEXTFOCUSBORDER ;
370 }
371 }
372 m_choice = new wxComboBoxChoice(this, style );
373
374 DoSetSize(pos.x, pos.y, csize.x, csize.y);
375
376 Append( n, choices );
377
378 // Needed because it is a wxControlWithItems
379 SetInitialSize(size);
380 SetStringSelection(value);
381
382 return true;
383}
384
385wxString wxComboBox::GetValue() const
386{
387 wxString result;
388
389 if ( m_text == NULL )
390 result = m_choice->GetString( m_choice->GetSelection() );
391 else
392 result = m_text->GetValue();
393
394 return result;
395}
396
397unsigned int wxComboBox::GetCount() const
398{
399 return m_choice->GetCount() ;
400}
401
402void wxComboBox::SetValue(const wxString& value)
403{
404 if ( HasFlag(wxCB_READONLY) )
405 SetStringSelection( value ) ;
406 else
407 m_text->SetValue( value );
408}
409
410void wxComboBox::WriteText(const wxString& text)
411{
412 m_text->WriteText(text);
413}
414
415void wxComboBox::GetSelection(long *from, long *to) const
416{
417 m_text->GetSelection(from, to);
418}
419
420// Clipboard operations
421
422void wxComboBox::Copy()
423{
424 if ( m_text != NULL )
425 m_text->Copy();
426}
427
428void wxComboBox::Cut()
429{
430 if ( m_text != NULL )
431 m_text->Cut();
432}
433
434void wxComboBox::Paste()
435{
436 if ( m_text != NULL )
437 m_text->Paste();
438}
439
440void wxComboBox::SetEditable(bool editable)
441{
442 if ( ( m_text == NULL ) && editable )
443 {
444 m_text = new wxComboBoxText( this );
445 }
446 else if ( ( m_text != NULL ) && !editable )
447 {
448 delete m_text;
449 m_text = NULL;
450 }
451
452 int currentX, currentY;
453 GetPosition( &currentX, &currentY );
454
455 int currentW, currentH;
456 GetSize( &currentW, &currentH );
457
458 DoMoveWindow( currentX, currentY, currentW, currentH );
459}
460
461void wxComboBox::SetInsertionPoint(long pos)
462{
463 if ( m_text )
464 m_text->SetInsertionPoint(pos);
465}
466
467void wxComboBox::SetInsertionPointEnd()
468{
469 if ( m_text )
470 m_text->SetInsertionPointEnd();
471}
472
473long wxComboBox::GetInsertionPoint() const
474{
475 if ( m_text )
476 return m_text->GetInsertionPoint();
477 return 0;
478}
479
480wxTextPos wxComboBox::GetLastPosition() const
481{
482 if ( m_text )
483 return m_text->GetLastPosition();
484 return 0;
485}
486
487void wxComboBox::Replace(long from, long to, const wxString& value)
488{
489 if ( m_text )
490 m_text->Replace(from,to,value);
491}
492
493void wxComboBox::Remove(long from, long to)
494{
495 if ( m_text )
496 m_text->Remove(from,to);
497}
498
499void wxComboBox::SetSelection(long from, long to)
500{
501 if ( m_text )
502 m_text->SetSelection(from,to);
503}
504
505int wxComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
506 unsigned int pos,
507 void **clientData,
508 wxClientDataType type)
509{
510 return m_choice->DoInsertItems(items, pos, clientData, type);
511}
512
513void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
514{
515 return m_choice->DoSetItemClientData( n , clientData ) ;
516}
517
518void* wxComboBox::DoGetItemClientData(unsigned int n) const
519{
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);
531}
532
533void wxComboBox::DoDeleteOneItem(unsigned int n)
534{
535 m_choice->DoDeleteOneItem( n );
536}
537
538void wxComboBox::DoClear()
539{
540 m_choice->DoClear();
541}
542
543int wxComboBox::GetSelection() const
544{
545 return m_choice->GetSelection();
546}
547
548void wxComboBox::SetSelection(int n)
549{
550 m_choice->SetSelection( n );
551
552 if ( m_text != NULL )
553 m_text->SetValue(n != wxNOT_FOUND ? GetString(n) : wxString(wxEmptyString));
554}
555
556int wxComboBox::FindString(const wxString& s, bool bCase) const
557{
558 return m_choice->FindString( s, bCase );
559}
560
561wxString wxComboBox::GetString(unsigned int n) const
562{
563 return m_choice->GetString( n );
564}
565
566wxString wxComboBox::GetStringSelection() const
567{
568 int sel = GetSelection();
569 if (sel != wxNOT_FOUND)
570 return wxString(this->GetString((unsigned int)sel));
571 else
572 return wxEmptyString;
573}
574
575void wxComboBox::SetString(unsigned int n, const wxString& s)
576{
577 m_choice->SetString( n , s );
578}
579
580bool wxComboBox::IsEditable() const
581{
582 return m_text != NULL && !HasFlag(wxCB_READONLY);
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}
642
524c47aa 643bool wxComboBox::HandleClicked( double timestampsec )
489468fe
SC
644{
645/*
646 For consistency with other platforms, clicking in the text area does not constitute a selection
647 wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, m_windowId );
648 event.SetInt(GetSelection());
649 event.SetEventObject(this);
650 event.SetString(GetStringSelection());
651 ProcessCommand(event);
652*/
653
524c47aa 654 return true ;
489468fe
SC
655}
656
657#endif // wxUSE_COMBOBOX