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