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