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