]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/combobox.cpp
SetSizeHints hacks are not needed any longer since the minsize is not
[wxWidgets.git] / src / mac / carbon / combobox.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
21 #if !USE_SHARED_LIBRARY
22 IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
23 #endif
24
25 // composite combobox implementation by Dan "Bud" Keith bud@otsys.com
26
27
28 static int nextPopUpMenuId = 1000 ;
29 MenuHandle NewUniqueMenu()
30 {
31 MenuHandle handle = NewMenu( nextPopUpMenuId , "\pMenu" ) ;
32 nextPopUpMenuId++ ;
33 return handle ;
34 }
35
36
37 // ----------------------------------------------------------------------------
38 // constants
39 // ----------------------------------------------------------------------------
40
41 // the margin between the text control and the choice
42 #if TARGET_API_MAC_OSX
43 // margin should be bigger on OS X due to blue highlight
44 // around text control.
45 static const wxCoord MARGIN = 6;
46 static const int POPUPWIDTH = 24;
47 #else
48 static const wxCoord MARGIN = 2;
49 static const int POPUPWIDTH = 18;
50 #endif
51 static const int POPUPHEIGHT = 23;
52
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
128 private:
129 wxComboBox *m_cb;
130
131 DECLARE_EVENT_TABLE()
132 };
133
134 BEGIN_EVENT_TABLE(wxComboBoxText, wxTextCtrl)
135 EVT_CHAR( wxComboBoxText::OnChar)
136 END_EVENT_TABLE()
137
138 class wxComboBoxChoice : public wxChoice
139 {
140 public:
141 wxComboBoxChoice(wxComboBox *cb, int style)
142 : wxChoice( cb , 1 )
143 {
144 m_cb = cb;
145 }
146
147 protected:
148 void OnChoice( wxCommandEvent& e )
149 {
150 wxString s = e.GetString();
151
152 m_cb->DelegateChoice( s );
153 wxCommandEvent event2(wxEVT_COMMAND_COMBOBOX_SELECTED, m_cb->GetId() );
154 event2.SetInt(m_cb->GetSelection());
155 event2.SetEventObject(m_cb);
156 event2.SetString(m_cb->GetStringSelection());
157 m_cb->ProcessCommand(event2);
158 }
159 virtual wxSize DoGetBestSize() const
160 {
161 wxSize sz = wxChoice::DoGetBestSize() ;
162 if (! m_cb->HasFlag(wxCB_READONLY) )
163 sz.x = POPUPWIDTH;
164 return sz ;
165 }
166
167 private:
168 wxComboBox *m_cb;
169
170 DECLARE_EVENT_TABLE()
171 };
172
173 BEGIN_EVENT_TABLE(wxComboBoxChoice, wxChoice)
174 EVT_CHOICE(-1, wxComboBoxChoice::OnChoice)
175 END_EVENT_TABLE()
176
177 wxComboBox::~wxComboBox()
178 {
179 // delete client objects
180 FreeData();
181
182 // delete the controls now, don't leave them alive even though they would
183 // still be eventually deleted by our parent - but it will be too late, the
184 // user code expects them to be gone now
185 if (m_text != NULL) {
186 delete m_text;
187 m_text = NULL;
188 }
189 if (m_choice != NULL) {
190 delete m_choice;
191 m_choice = NULL;
192 }
193 }
194
195
196 // ----------------------------------------------------------------------------
197 // geometry
198 // ----------------------------------------------------------------------------
199
200 wxSize wxComboBox::DoGetBestSize() const
201 {
202 if (!m_choice && !m_text)
203 return GetSize();
204 wxSize size = m_choice->GetBestSize();
205
206 if ( m_text != NULL )
207 {
208 wxSize sizeText = m_text->GetBestSize();
209 if (sizeText.y > size.y)
210 size.y = sizeText.y;
211 size.x = POPUPWIDTH + sizeText.x + MARGIN;
212 }
213
214 return size;
215 }
216
217 void wxComboBox::DoMoveWindow(int x, int y, int width, int height) {
218 height = POPUPHEIGHT;
219 int origin = 0;
220 #if TARGET_API_MAC_OSX
221 // give the controls some padding so that the text ctrl's borders
222 // and blue highlight can appear
223 origin = 4;
224 #endif
225
226 wxControl::DoMoveWindow(x, y, width + origin, height + origin);
227
228 if ( m_text == NULL )
229 {
230 // we might not be fully constructed yet, therefore watch out...
231 if ( m_choice )
232 m_choice->SetSize(0, 0 , width, -1);
233 }
234 else
235 {
236 wxCoord wText = width - POPUPWIDTH - MARGIN;
237 #if TARGET_API_MAC_OSX
238 // also, we need to shrink the size of the wxTextCtrl a bit
239 // to make it appear properly on OS X.
240 height -= 8;
241 wText -= 8;
242 #endif
243 m_text->SetSize(origin, origin, wText, height);
244 m_choice->SetSize(origin + wText + MARGIN, 0, POPUPWIDTH, -1);
245 }
246 }
247
248
249
250 // ----------------------------------------------------------------------------
251 // operations forwarded to the subcontrols
252 // ----------------------------------------------------------------------------
253
254 bool wxComboBox::Enable(bool enable)
255 {
256 if ( !wxControl::Enable(enable) )
257 return FALSE;
258
259 return TRUE;
260 }
261
262 bool wxComboBox::Show(bool show)
263 {
264 if ( !wxControl::Show(show) )
265 return FALSE;
266
267 return TRUE;
268 }
269
270 void wxComboBox::SetFocus()
271 {
272 if ( m_text != NULL) {
273 m_text->SetFocus();
274 }
275 }
276
277
278 void wxComboBox::DelegateTextChanged( const wxString& value )
279 {
280 SetStringSelection( value );
281 }
282
283
284 void wxComboBox::DelegateChoice( const wxString& value )
285 {
286 SetStringSelection( value );
287 }
288
289
290 bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
291 const wxString& value,
292 const wxPoint& pos,
293 const wxSize& size,
294 const wxArrayString& choices,
295 long style,
296 const wxValidator& validator,
297 const wxString& name)
298 {
299 wxCArrayString chs( choices );
300
301 return Create( parent, id, value, pos, size, chs.GetCount(),
302 chs.GetStrings(), style, validator, name );
303 }
304
305
306 bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
307 const wxString& value,
308 const wxPoint& pos,
309 const wxSize& size,
310 int n, const wxString choices[],
311 long style,
312 const wxValidator& validator,
313 const wxString& name)
314 {
315 if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style ,
316 wxDefaultValidator, name) )
317 {
318 return FALSE;
319 }
320
321 m_choice = new wxComboBoxChoice(this, style );
322 wxSize csize = size;
323 if ( style & wxCB_READONLY )
324 {
325 m_text = NULL;
326 }
327 else
328 {
329 m_text = new wxComboBoxText(this);
330 if ( size.y == -1 ) {
331 csize.y = m_text->GetSize().y ;
332 }
333 }
334
335 DoSetSize(pos.x, pos.y, csize.x, csize.y);
336
337 for ( int i = 0 ; i < n ; i++ )
338 {
339 m_choice->DoAppend( choices[ i ] );
340 }
341
342 SetBestSize(size); // Needed because it is a wxControlWithItems
343
344 return TRUE;
345 }
346
347 wxString wxComboBox::GetValue() const
348 {
349 wxString result;
350
351 if ( m_text == NULL )
352 {
353 result = m_choice->GetString( m_choice->GetSelection() );
354 }
355 else
356 {
357 result = m_text->GetValue();
358 }
359
360 return result;
361 }
362
363 int wxComboBox::GetCount() const
364 {
365 return m_choice->GetCount() ;
366 }
367
368 void wxComboBox::SetValue(const wxString& value)
369 {
370 int s = FindString (value);
371 if (s == wxNOT_FOUND && !HasFlag(wxCB_READONLY) )
372 {
373 m_choice->Append(value) ;
374 }
375 SetStringSelection( value ) ;
376 }
377
378 // Clipboard operations
379 void wxComboBox::Copy()
380 {
381 if ( m_text != NULL )
382 {
383 m_text->Copy();
384 }
385 }
386
387 void wxComboBox::Cut()
388 {
389 if ( m_text != NULL )
390 {
391 m_text->Cut();
392 }
393 }
394
395 void wxComboBox::Paste()
396 {
397 if ( m_text != NULL )
398 {
399 m_text->Paste();
400 }
401 }
402
403 void wxComboBox::SetEditable(bool editable)
404 {
405 if ( ( m_text == NULL ) && editable )
406 {
407 m_text = new wxComboBoxText( this );
408 }
409 else if ( ( m_text != NULL ) && !editable )
410 {
411 delete m_text;
412 m_text = NULL;
413 }
414
415 int currentX, currentY;
416 GetPosition( &currentX, &currentY );
417
418 int currentW, currentH;
419 GetSize( &currentW, &currentH );
420
421 DoMoveWindow( currentX, currentY, currentW, currentH );
422 }
423
424 void wxComboBox::SetInsertionPoint(long pos)
425 {
426 // TODO
427 }
428
429 void wxComboBox::SetInsertionPointEnd()
430 {
431 // TODO
432 }
433
434 long wxComboBox::GetInsertionPoint() const
435 {
436 // TODO
437 return 0;
438 }
439
440 long wxComboBox::GetLastPosition() const
441 {
442 // TODO
443 return 0;
444 }
445
446 void wxComboBox::Replace(long from, long to, const wxString& value)
447 {
448 // TODO
449 }
450
451 void wxComboBox::Remove(long from, long to)
452 {
453 // TODO
454 }
455
456 void wxComboBox::SetSelection(long from, long to)
457 {
458 // TODO
459 }
460
461 int wxComboBox::DoAppend(const wxString& item)
462 {
463 return m_choice->DoAppend( item ) ;
464 }
465
466 int wxComboBox::DoInsert(const wxString& item, int pos)
467 {
468 return m_choice->DoInsert( item , pos ) ;
469 }
470
471 void wxComboBox::DoSetItemClientData(int n, void* clientData)
472 {
473 return m_choice->DoSetItemClientData( n , clientData ) ;
474 }
475
476 void* wxComboBox::DoGetItemClientData(int n) const
477 {
478 return m_choice->DoGetItemClientData( n ) ;
479 }
480
481 void wxComboBox::DoSetItemClientObject(int n, wxClientData* clientData)
482 {
483 return m_choice->DoSetItemClientObject( n , clientData ) ;
484 }
485
486 wxClientData* wxComboBox::DoGetItemClientObject(int n) const
487 {
488 return m_choice->DoGetItemClientObject( n ) ;
489 }
490
491 void wxComboBox::FreeData()
492 {
493 if ( HasClientObjectData() )
494 {
495 size_t count = GetCount();
496 for ( size_t n = 0; n < count; n++ )
497 {
498 SetClientObject( n, NULL );
499 }
500 }
501 }
502
503 void wxComboBox::Delete(int n)
504 {
505 // force client object deletion
506 if( HasClientObjectData() )
507 SetClientObject( n, NULL );
508 m_choice->Delete( n );
509 }
510
511 void wxComboBox::Clear()
512 {
513 FreeData();
514 m_choice->Clear();
515 }
516
517 int wxComboBox::GetSelection() const
518 {
519 return m_choice->GetSelection();
520 }
521
522 void wxComboBox::SetSelection(int n)
523 {
524 m_choice->SetSelection( n );
525
526 if ( m_text != NULL )
527 {
528 m_text->SetValue( GetString( n ) );
529 }
530 }
531
532 int wxComboBox::FindString(const wxString& s) const
533 {
534 return m_choice->FindString( s );
535 }
536
537 wxString wxComboBox::GetString(int n) const
538 {
539 return m_choice->GetString( n );
540 }
541
542 wxString wxComboBox::GetStringSelection() const
543 {
544 int sel = GetSelection ();
545 if (sel > -1)
546 return wxString(this->GetString (sel));
547 else
548 return wxEmptyString;
549 }
550
551 bool wxComboBox::SetStringSelection(const wxString& sel)
552 {
553 int s = FindString (sel);
554 if (s > -1)
555 {
556 SetSelection (s);
557 return TRUE;
558 }
559 else
560 return FALSE;
561 }
562
563 void wxComboBox::SetString(int n, const wxString& s)
564 {
565 m_choice->SetString( n , s ) ;
566 }
567
568
569 wxInt32 wxComboBox::MacControlHit(WXEVENTHANDLERREF WXUNUSED(handler) , WXEVENTREF WXUNUSED(event) )
570 {
571 wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, m_windowId );
572 event.SetInt(GetSelection());
573 event.SetEventObject(this);
574 event.SetString(GetStringSelection());
575 ProcessCommand(event);
576 return noErr ;
577 }
578