]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/combobxc.cpp
Fix crash in wxDC::GetMultiLineTextExtent() after last commit.
[wxWidgets.git] / src / osx / carbon / combobxc.cpp
CommitLineData
489468fe 1/////////////////////////////////////////////////////////////////////////////
524c47aa 2// Name: src/osx/carbon/combobxc.cpp
489468fe
SC
3// Purpose: wxComboBox class using HIView ComboBox
4// Author: Stefan Csomor
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#include "wx/combobox.h"
15
16#ifndef WX_PRECOMP
17 #include "wx/button.h"
18 #include "wx/menu.h"
19#endif
20
1f0c8f31 21#include "wx/osx/uma.h"
489468fe
SC
22#if TARGET_API_MAC_OSX
23#ifndef __HIVIEW__
24 #include <HIToolbox/HIView.h>
25#endif
26#endif
27
489468fe
SC
28#if TARGET_API_MAC_OSX
29#define USE_HICOMBOBOX 1 //use hi combobox define
30#else
31#define USE_HICOMBOBOX 0
32#endif
33
34static int nextPopUpMenuId = 1000;
35MenuHandle NewUniqueMenu()
36{
37 MenuHandle handle = NewMenu( nextPopUpMenuId , "\pMenu" );
38 nextPopUpMenuId++;
39 return handle;
40}
41
42#if USE_HICOMBOBOX
43static const EventTypeSpec eventList[] =
44{
45 { kEventClassTextField , kEventTextAccepted } ,
46};
47
48static pascal OSStatus wxMacComboBoxEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
49{
50 OSStatus result = eventNotHandledErr;
51 wxComboBox* cb = (wxComboBox*) data;
52
53 wxMacCarbonEvent cEvent( event );
54
55 switch( cEvent.GetClass() )
56 {
57 case kEventClassTextField :
58 switch( cEvent.GetKind() )
59 {
60 case kEventTextAccepted :
61 {
62 wxCommandEvent event( wxEVT_COMMAND_COMBOBOX_SELECTED, cb->GetId() );
63 event.SetInt( cb->GetSelection() );
64 event.SetString( cb->GetStringSelection() );
65 event.SetEventObject( cb );
66 cb->HandleWindowEvent( event );
67 }
68 break;
69 default :
70 break;
71 }
72 break;
73 default :
74 break;
75 }
76
77
78 return result;
79}
80
81DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacComboBoxEventHandler )
82
83#endif
84
85// ----------------------------------------------------------------------------
86// constants
87// ----------------------------------------------------------------------------
88
89// the margin between the text control and the choice
90static const wxCoord MARGIN = 2;
91#if TARGET_API_MAC_OSX
92static const int POPUPWIDTH = 24;
93#else
94static const int POPUPWIDTH = 18;
95#endif
96static const int POPUPHEIGHT = 23;
97
98// ----------------------------------------------------------------------------
99// wxComboBoxText: text control forwards events to combobox
100// ----------------------------------------------------------------------------
101
102class wxComboBoxText : public wxTextCtrl
103{
104public:
105 wxComboBoxText( wxComboBox * cb )
106 : wxTextCtrl( cb , 1 )
107 {
108 m_cb = cb;
109 }
110
111protected:
112 void OnChar( wxKeyEvent& event )
113 {
114 if ( event.GetKeyCode() == WXK_RETURN )
115 {
116 wxString value = GetValue();
117
118 if ( m_cb->GetCount() == 0 )
119 {
120 // make Enter generate "selected" event if there is only one item
121 // in the combobox - without it, it's impossible to select it at
122 // all!
123 wxCommandEvent event( wxEVT_COMMAND_COMBOBOX_SELECTED, m_cb->GetId() );
124 event.SetInt( 0 );
125 event.SetString( value );
126 event.SetEventObject( m_cb );
127 m_cb->HandleWindowEvent( event );
128 }
129 else
130 {
131 // add the item to the list if it's not there yet
132 if ( m_cb->FindString(value) == wxNOT_FOUND )
133 {
134 m_cb->Append(value);
135 m_cb->SetStringSelection(value);
136
137 // and generate the selected event for it
138 wxCommandEvent event( wxEVT_COMMAND_COMBOBOX_SELECTED, m_cb->GetId() );
139 event.SetInt( m_cb->GetCount() - 1 );
140 event.SetString( value );
141 event.SetEventObject( m_cb );
142 m_cb->HandleWindowEvent( event );
143 }
144
145 // This will invoke the dialog default action, such
146 // as the clicking the default button.
147
148 wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
149 if ( tlw && tlw->GetDefaultItem() )
150 {
151 wxButton *def = wxDynamicCast(tlw->GetDefaultItem(), wxButton);
152 if ( def && def->IsEnabled() )
153 {
154 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
155 event.SetEventObject(def);
156 def->Command(event);
157 return;
158 }
159 }
160
161 return;
162 }
163 }
164
165 event.Skip();
166 }
167private:
168 wxComboBox *m_cb;
169
170 DECLARE_EVENT_TABLE()
171};
172
173BEGIN_EVENT_TABLE(wxComboBoxText, wxTextCtrl)
174 EVT_CHAR( wxComboBoxText::OnChar)
175END_EVENT_TABLE()
176
177class wxComboBoxChoice : public wxChoice
178{
179public:
180 wxComboBoxChoice(wxComboBox *cb, int style)
181 : wxChoice( cb , 1 )
182 {
183 m_cb = cb;
184 }
185
186protected:
187 void OnChoice( wxCommandEvent& e )
188 {
189 wxString s = e.GetString();
190
191 m_cb->DelegateChoice( s );
192 wxCommandEvent event2(wxEVT_COMMAND_COMBOBOX_SELECTED, m_cb->GetId() );
193 event2.SetInt(m_cb->GetSelection());
194 event2.SetEventObject(m_cb);
195 event2.SetString(m_cb->GetStringSelection());
196 m_cb->ProcessCommand(event2);
197 }
198 virtual wxSize DoGetBestSize() const
199 {
200 wxSize sz = wxChoice::DoGetBestSize();
201 sz.x = POPUPWIDTH;
202 return sz;
203 }
204
205private:
206 wxComboBox *m_cb;
207
208 DECLARE_EVENT_TABLE()
209};
210
211BEGIN_EVENT_TABLE(wxComboBoxChoice, wxChoice)
212 EVT_CHOICE(wxID_ANY, wxComboBoxChoice::OnChoice)
213END_EVENT_TABLE()
214
215wxComboBox::~wxComboBox()
216{
217 // delete the controls now, don't leave them alive even though they would
218 // still be eventually deleted by our parent - but it will be too late, the
219 // user code expects them to be gone now
524c47aa
SC
220 wxDELETE( m_text );
221 wxDELETE( m_choice );
489468fe
SC
222}
223
224
225// ----------------------------------------------------------------------------
226// geometry
227// ----------------------------------------------------------------------------
228
229wxSize wxComboBox::DoGetBestSize() const
230{
231#if USE_HICOMBOBOX
232 return wxControl::DoGetBestSize();
233#else
234 wxSize size = m_choice->GetBestSize();
235
236 if ( m_text != NULL )
237 {
238 wxSize sizeText = m_text->GetBestSize();
239
240 size.x = POPUPWIDTH + sizeText.x + MARGIN;
241 }
242
243 return size;
244#endif
245}
246
247void wxComboBox::DoMoveWindow(int x, int y, int width, int height) {
248#if USE_HICOMBOBOX
249 wxControl::DoMoveWindow(x, y, width, height);
250#else
251 height = POPUPHEIGHT;
252
253 wxControl::DoMoveWindow(x, y, width, height);
254
255 if ( m_text == NULL )
256 {
257 // we might not be fully constructed yet, therefore watch out...
258 if ( m_choice )
259 m_choice->SetSize(0, 0 , width, wxDefaultCoord);
260 }
261 else
262 {
263 wxCoord wText = width - POPUPWIDTH - MARGIN;
264 m_text->SetSize(0, 0, wText, height);
265 m_choice->SetSize(0 + wText + MARGIN, 0, POPUPWIDTH, wxDefaultCoord);
266 }
267#endif
268}
269
270
271
272// ----------------------------------------------------------------------------
273// operations forwarded to the subcontrols
274// ----------------------------------------------------------------------------
275
276bool wxComboBox::Enable(bool enable)
277{
278 if ( !wxControl::Enable(enable) )
279 return false;
280
281 return true;
282}
283
284bool wxComboBox::Show(bool show)
285{
286 if ( !wxControl::Show(show) )
287 return false;
288
289 return true;
290}
291
292void wxComboBox::SetFocus()
293{
294#if USE_HICOMBOBOX
295 wxControl::SetFocus();
296#else
297 if ( m_text != NULL) {
298 m_text->SetFocus();
299 }
300#endif
301}
302
303
304void wxComboBox::DelegateTextChanged( const wxString& value )
305{
306 SetStringSelection( value );
307}
308
309
310void wxComboBox::DelegateChoice( const wxString& value )
311{
312 SetStringSelection( value );
313}
314
315
316bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
317 const wxString& value,
318 const wxPoint& pos,
319 const wxSize& size,
320 const wxArrayString& choices,
321 long style,
322 const wxValidator& validator,
323 const wxString& name)
324{
325 wxCArrayString chs( choices );
326
327 return Create( parent, id, value, pos, size, chs.GetCount(),
328 chs.GetStrings(), style, validator, name );
329}
330
331
332bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
333 const wxString& value,
334 const wxPoint& pos,
335 const wxSize& size,
336 int n, const wxString choices[],
337 long style,
338 const wxValidator& validator,
339 const wxString& name)
340{
341 m_text = NULL;
342 m_choice = NULL;
343#if USE_HICOMBOBOX
d15694e8 344 DontCreatePeer();
489468fe
SC
345#endif
346 if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style ,
347 wxDefaultValidator, name) )
348 {
349 return false;
350 }
351#if USE_HICOMBOBOX
352 Rect bounds = wxMacGetBoundsForControl( this , pos , size );
353 HIRect hiRect;
354
355 hiRect.origin.x = 20; //bounds.left;
356 hiRect.origin.y = 25; //bounds.top;
357 hiRect.size.width = 120;// bounds.right - bounds.left;
358 hiRect.size.height = 24;
359
360 //For some reason, this code causes the combo box not to be displayed at all.
361 //hiRect.origin.x = bounds.left;
362 //hiRect.origin.y = bounds.top;
363 //hiRect.size.width = bounds.right - bounds.left;
364 //hiRect.size.height = bounds.bottom - bounds.top;
365 //printf("left = %d, right = %d, top = %d, bottom = %d\n", bounds.left, bounds.right, bounds.top, bounds.bottom);
366 //printf("x = %d, y = %d, width = %d, height = %d\n", hibounds.origin.x, hibounds.origin.y, hibounds.size.width, hibounds.size.height);
367 m_peer = new wxMacControl(this);
368 verify_noerr( HIComboBoxCreate( &hiRect, CFSTR(""), NULL, NULL, kHIComboBoxStandardAttributes, m_peer->GetControlRefAddr() ) );
369
370
371 m_peer->SetMinimum( 0 );
372 m_peer->SetMaximum( 100);
373 if ( n > 0 )
374 m_peer->SetValue( 1 );
375
376 MacPostControlCreate(pos,size);
377
378 Append( choices[ i ] );
379
380 HIViewSetVisible( m_peer->GetControlRef(), true );
381 SetSelection(0);
382 EventHandlerRef comboEventHandler;
383 InstallControlEventHandler( m_peer->GetControlRef(), GetwxMacComboBoxEventHandlerUPP(),
384 GetEventTypeCount(eventList), eventList, this,
385 (EventHandlerRef *)&comboEventHandler);
386#else
387 m_choice = new wxComboBoxChoice(this, style );
388 m_choice->SetMinSize( wxSize( POPUPWIDTH , POPUPHEIGHT ) );
389
390 wxSize csize = size;
391 if ( style & wxCB_READONLY )
392 {
393 m_text = NULL;
394 }
395 else
396 {
397 m_text = new wxComboBoxText(this);
398 if ( size.y == wxDefaultCoord ) {
399 csize.y = m_text->GetSize().y;
400 }
401 }
402
403 DoSetSize(pos.x, pos.y, csize.x, csize.y);
404
405 m_choice->Append( n, choices );
406 SetInitialSize(csize); // Needed because it is a wxControlWithItems
407#endif
408
409 return true;
410}
411
412wxString wxComboBox::GetValue() const
413{
414#if USE_HICOMBOBOX
415 CFStringRef myString;
416 HIComboBoxCopyTextItemAtIndex( m_peer->GetControlRef(), (CFIndex)GetSelection(), &myString );
417 return wxMacCFStringHolder( myString, GetFont().GetEncoding() ).AsString();
418#else
419 wxString result;
420
421 if ( m_text == NULL )
422 {
423 result = m_choice->GetString( m_choice->GetSelection() );
424 }
425 else
426 {
427 result = m_text->GetValue();
428 }
429
430 return result;
431#endif
432}
433
434void wxComboBox::SetValue(const wxString& value)
435{
436#if USE_HICOMBOBOX
437
438#else
439 int s = FindString (value);
440 if (s == wxNOT_FOUND && !HasFlag(wxCB_READONLY) )
441 {
442 m_choice->Append(value);
443 }
444 SetStringSelection( value );
445#endif
446}
447
448// Clipboard operations
449void wxComboBox::Copy()
450{
451 if ( m_text != NULL )
452 {
453 m_text->Copy();
454 }
455}
456
457void wxComboBox::Cut()
458{
459 if ( m_text != NULL )
460 {
461 m_text->Cut();
462 }
463}
464
465void wxComboBox::Paste()
466{
467 if ( m_text != NULL )
468 {
469 m_text->Paste();
470 }
471}
472
473void wxComboBox::SetEditable(bool editable)
474{
475 if ( ( m_text == NULL ) && editable )
476 {
477 m_text = new wxComboBoxText( this );
478 }
5276b0a5 479 else if ( !editable )
489468fe 480 {
5276b0a5 481 wxDELETE(m_text);
489468fe
SC
482 }
483
484 int currentX, currentY;
485 GetPosition( &currentX, &currentY );
486
487 int currentW, currentH;
488 GetSize( &currentW, &currentH );
489
490 DoMoveWindow( currentX, currentY, currentW, currentH );
491}
492
493void wxComboBox::SetInsertionPoint(long pos)
494{
495 // TODO
496}
497
498void wxComboBox::SetInsertionPointEnd()
499{
500 // TODO
501}
502
503long wxComboBox::GetInsertionPoint() const
504{
505 // TODO
506 return 0;
507}
508
509wxTextPos wxComboBox::GetLastPosition() const
510{
511 // TODO
512 return 0;
513}
514
515void wxComboBox::Replace(long from, long to, const wxString& value)
516{
517 // TODO
518}
519
520void wxComboBox::Remove(long from, long to)
521{
522 // TODO
523}
524
525void wxComboBox::SetSelection(long from, long to)
526{
527 // TODO
528}
529
530int wxComboBox::DoInsertItems(const wxArrayStringsAdapter& items,
531 unsigned int pos,
532 void **clientData, wxClientDataType type)
533{
534#if USE_HICOMBOBOX
535 const unsigned int count = items.GetCount();
536 for ( unsigned int i = 0; i < count; ++i, ++pos )
537 {
538 HIComboBoxInsertTextItemAtIndex(m_peer->GetControlRef(),
539 (CFIndex)pos,
540 wxMacCFStringHolder(items[i],
541 GetFont().GetEncoding()));
542 AssignNewItemClientData(pos, clientData, i, type);
543 }
544
545 //SetControl32BitMaximum( m_peer->GetControlRef(), GetCount() );
546
547 return pos - 1;
548#else
549 return m_choice->DoInsertItems( items, pos, clientData, type );
550#endif
551}
552
553void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
554{
555#if USE_HICOMBOBOX
556 return; //TODO
557#else
558 return m_choice->DoSetItemClientData( n , clientData );
559#endif
560}
561
562void* wxComboBox::DoGetItemClientData(unsigned int n) const
563{
564#if USE_HICOMBOBOX
565 return NULL; //TODO
566#else
567 return m_choice->DoGetItemClientData( n );
568#endif
569}
570
571unsigned int wxComboBox::GetCount() const {
572#if USE_HICOMBOBOX
573 return (unsigned int) HIComboBoxGetItemCount( m_peer->GetControlRef() );
574#else
575 return m_choice->GetCount();
576#endif
577}
578
579void wxComboBox::DoDeleteOneItem(unsigned int n)
580{
581#if USE_HICOMBOBOX
582 HIComboBoxRemoveItemAtIndex( m_peer->GetControlRef(), (CFIndex)n );
583#else
584 m_choice->Delete( n );
585#endif
586}
587
588void wxComboBox::DoClear()
589{
590#if USE_HICOMBOBOX
591 for ( CFIndex i = GetCount() - 1; i >= 0; ++ i )
592 verify_noerr( HIComboBoxRemoveItemAtIndex( m_peer->GetControlRef(), i ) );
593 m_peer->SetData<CFStringRef>(kHIComboBoxEditTextPart,kControlEditTextCFStringTag,CFSTR(""));
594#else
595 m_choice->Clear();
596#endif
597}
598
599int wxComboBox::GetSelection() const
600{
601#if USE_HICOMBOBOX
602 return FindString( GetStringSelection() );
603#else
604 return m_choice->GetSelection();
605#endif
606}
607
608void wxComboBox::SetSelection(int n)
609{
610#if USE_HICOMBOBOX
611 SetControl32BitValue( m_peer->GetControlRef() , n + 1 );
612#else
613 m_choice->SetSelection( n );
614
615 if ( m_text != NULL )
616 {
617 m_text->SetValue(GetString(n));
618 }
619#endif
620}
621
622int wxComboBox::FindString(const wxString& s, bool bCase) const
623{
624#if USE_HICOMBOBOX
625 for( unsigned int i = 0 ; i < GetCount() ; i++ )
626 {
627 if (GetString(i).IsSameAs(s, bCase) )
628 return i ;
629 }
630 return wxNOT_FOUND;
631#else
632 return m_choice->FindString( s, bCase );
633#endif
634}
635
636wxString wxComboBox::GetString(unsigned int n) const
637{
638#if USE_HICOMBOBOX
639 CFStringRef itemText;
640 HIComboBoxCopyTextItemAtIndex( m_peer->GetControlRef(), (CFIndex)n, &itemText );
641 return wxMacCFStringHolder(itemText).AsString();
642#else
643 return m_choice->GetString( n );
644#endif
645}
646
647wxString wxComboBox::GetStringSelection() const
648{
649#if USE_HICOMBOBOX
650 return wxMacCFStringHolder(m_peer->GetData<CFStringRef>(kHIComboBoxEditTextPart,kControlEditTextCFStringTag)).AsString();
651#else
652 int sel = GetSelection ();
653 if (sel != wxNOT_FOUND)
654 return wxString(this->GetString((unsigned int)sel));
655 else
656 return wxEmptyString;
657#endif
658}
659
660void wxComboBox::SetString(unsigned int n, const wxString& s)
661{
662#if USE_HICOMBOBOX
663 verify_noerr ( HIComboBoxInsertTextItemAtIndex( m_peer->GetControlRef(), (CFIndex) n,
664 wxMacCFStringHolder(s, GetFont().GetEncoding()) ) );
665 verify_noerr ( HIComboBoxRemoveItemAtIndex( m_peer->GetControlRef(), (CFIndex) n + 1 ) );
666#else
667 m_choice->SetString( n , s );
668#endif
669}
670
671bool wxComboBox::IsEditable() const
672{
673#if USE_HICOMBOBOX
674 // TODO
675 return !HasFlag(wxCB_READONLY);
676#else
677 return m_text != NULL && !HasFlag(wxCB_READONLY);
678#endif
679}
680
681void wxComboBox::Undo()
682{
683#if USE_HICOMBOBOX
684 // TODO
685#else
686 if (m_text != NULL)
687 m_text->Undo();
688#endif
689}
690
691void wxComboBox::Redo()
692{
693#if USE_HICOMBOBOX
694 // TODO
695#else
696 if (m_text != NULL)
697 m_text->Redo();
698#endif
699}
700
701void wxComboBox::SelectAll()
702{
703#if USE_HICOMBOBOX
704 // TODO
705#else
706 if (m_text != NULL)
707 m_text->SelectAll();
708#endif
709}
710
711bool wxComboBox::CanCopy() const
712{
713#if USE_HICOMBOBOX
714 // TODO
715 return false;
716#else
717 if (m_text != NULL)
718 return m_text->CanCopy();
719 else
720 return false;
721#endif
722}
723
724bool wxComboBox::CanCut() const
725{
726#if USE_HICOMBOBOX
727 // TODO
728 return false;
729#else
730 if (m_text != NULL)
731 return m_text->CanCut();
732 else
733 return false;
734#endif
735}
736
737bool wxComboBox::CanPaste() const
738{
739#if USE_HICOMBOBOX
740 // TODO
741 return false;
742#else
743 if (m_text != NULL)
744 return m_text->CanPaste();
745 else
746 return false;
747#endif
748}
749
750bool wxComboBox::CanUndo() const
751{
752#if USE_HICOMBOBOX
753 // TODO
754 return false;
755#else
756 if (m_text != NULL)
757 return m_text->CanUndo();
758 else
759 return false;
760#endif
761}
762
763bool wxComboBox::CanRedo() const
764{
765#if USE_HICOMBOBOX
766 // TODO
767 return false;
768#else
769 if (m_text != NULL)
770 return m_text->CanRedo();
771 else
772 return false;
773#endif
774}
775
4eb5a0ec 776bool wxComboBox::OSXHandleClicked( double timestampsec )
489468fe
SC
777{
778 wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, m_windowId );
779 event.SetInt(GetSelection());
780 event.SetEventObject(this);
781 event.SetString(GetStringSelection());
782 ProcessCommand(event);
524c47aa 783 return true;
489468fe 784}