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