]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/mac/carbon/combobox.cpp
Fix overflow warnings (?)
[wxWidgets.git] / src / mac / carbon / combobox.cpp
... / ...
CommitLineData
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
22IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
23#endif
24
25// composite combobox implementation by Dan "Bud" Keith bud@otsys.com
26
27
28static int nextPopUpMenuId = 1000 ;
29MenuHandle 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.
45static const wxCoord MARGIN = 4;
46// this is the border a focus rect on OSX is needing
47static const int TEXTFOCUSBORDER = 3 ;
48#else
49static const wxCoord MARGIN = 2;
50static const int TEXTFOCUSBORDER = 0 ;
51#endif
52static const int POPUPHEIGHT = 23;
53
54
55// ----------------------------------------------------------------------------
56// wxComboBoxText: text control forwards events to combobox
57// ----------------------------------------------------------------------------
58
59class wxComboBoxText : public wxTextCtrl
60{
61public:
62 wxComboBoxText( wxComboBox * cb )
63 : wxTextCtrl( cb , 1 )
64 {
65 m_cb = cb;
66 }
67
68protected:
69 void OnChar( wxKeyEvent& event )
70 {
71 // Allows processing the tab key to go to the next control
72 if (event.GetKeyCode() == WXK_TAB)
73 {
74 wxNavigationKeyEvent NavEvent;
75 NavEvent.SetEventObject(this);
76 NavEvent.SetDirection(true);
77 NavEvent.SetWindowChange(false);
78
79 // Get the parent of the combo and have it process the navigation?
80 if (m_cb->GetParent()->GetEventHandler()->ProcessEvent(NavEvent))
81 return;
82 }
83 if ( event.GetKeyCode() == WXK_RETURN )
84 {
85 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_cb->GetId());
86 event.SetString( GetValue() );
87 event.SetInt( m_cb->GetSelection() );
88 event.SetEventObject( m_cb );
89
90 // This will invoke the dialog default action, such
91 // as the clicking the default button.
92
93 if (!m_cb->GetEventHandler()->ProcessEvent( event ))
94 {
95 wxWindow *parent = GetParent();
96 while( parent && !parent->IsTopLevel() && parent->GetDefaultItem() == NULL ) {
97 parent = parent->GetParent() ;
98 }
99 if ( parent && parent->GetDefaultItem() )
100 {
101 wxButton *def = wxDynamicCast(parent->GetDefaultItem(),
102 wxButton);
103 if ( def && def->IsEnabled() )
104 {
105 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, def->GetId() );
106 event.SetEventObject(def);
107 def->Command(event);
108 }
109 }
110
111 return;
112 }
113 }
114
115 event.Skip();
116 }
117
118 // Use the KeyUp as a naive approximation for TEXT_UPDATED, even though it is somewhat delayed
119 // but this is less complicated than dealing with idle-ness, and is much better than nothing
120 void OnKeyUp( wxKeyEvent& event )
121 {
122 if ( event.GetKeyCode() != WXK_RETURN )
123 {
124 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_cb->GetId());
125 event.SetString( GetValue() );
126 event.SetEventObject( m_cb );
127 m_cb->GetEventHandler()->ProcessEvent(event);
128 }
129 }
130private:
131 wxComboBox *m_cb;
132
133 DECLARE_EVENT_TABLE()
134};
135
136BEGIN_EVENT_TABLE(wxComboBoxText, wxTextCtrl)
137 EVT_CHAR( wxComboBoxText::OnChar)
138 EVT_KEY_UP( wxComboBoxText::OnKeyUp)
139END_EVENT_TABLE()
140
141class wxComboBoxChoice : public wxChoice
142{
143public:
144 wxComboBoxChoice(wxComboBox *cb, int style)
145 : wxChoice( cb , 1 )
146 {
147 m_cb = cb;
148 }
149 int GetPopupWidth() const
150 {
151 switch ( GetWindowVariant() )
152 {
153 case wxWINDOW_VARIANT_NORMAL :
154 case wxWINDOW_VARIANT_LARGE :
155 return 24 ;
156 default :
157 return 21 ;
158 }
159 }
160
161protected:
162 void OnChoice( wxCommandEvent& e )
163 {
164 wxString s = e.GetString();
165
166 m_cb->DelegateChoice( s );
167 wxCommandEvent event2(wxEVT_COMMAND_COMBOBOX_SELECTED, m_cb->GetId() );
168 event2.SetInt(m_cb->GetSelection());
169 event2.SetEventObject(m_cb);
170 event2.SetString(m_cb->GetStringSelection());
171 m_cb->ProcessCommand(event2);
172
173 // For consistency with MSW and GTK, also send a text updated event
174 // After all, the text is updated when a selection is made
175 wxCommandEvent TextEvent( wxEVT_COMMAND_TEXT_UPDATED, m_cb->GetId() );
176 TextEvent.SetString( m_cb->GetStringSelection() );
177 TextEvent.SetEventObject( m_cb );
178 m_cb->ProcessCommand( TextEvent );
179 }
180 virtual wxSize DoGetBestSize() const
181 {
182 wxSize sz = wxChoice::DoGetBestSize() ;
183 if (! m_cb->HasFlag(wxCB_READONLY) )
184 sz.x = GetPopupWidth() ;
185 return sz ;
186 }
187
188private:
189 wxComboBox *m_cb;
190
191 DECLARE_EVENT_TABLE()
192};
193
194BEGIN_EVENT_TABLE(wxComboBoxChoice, wxChoice)
195 EVT_CHOICE(-1, wxComboBoxChoice::OnChoice)
196END_EVENT_TABLE()
197
198wxComboBox::~wxComboBox()
199{
200 // delete client objects
201 FreeData();
202
203 // delete the controls now, don't leave them alive even though they would
204 // still be eventually deleted by our parent - but it will be too late, the
205 // user code expects them to be gone now
206 if (m_text != NULL) {
207 delete m_text;
208 m_text = NULL;
209 }
210 if (m_choice != NULL) {
211 delete m_choice;
212 m_choice = NULL;
213 }
214}
215
216
217// ----------------------------------------------------------------------------
218// geometry
219// ----------------------------------------------------------------------------
220
221wxSize wxComboBox::DoGetBestSize() const
222{
223 if (!m_choice && !m_text)
224 return GetSize();
225 wxSize size = m_choice->GetBestSize();
226
227 if ( m_text != NULL )
228 {
229 wxSize sizeText = m_text->GetBestSize();
230 if (sizeText.y > size.y)
231 size.y = sizeText.y;
232 size.x = m_choice->GetPopupWidth() + sizeText.x + MARGIN;
233 size.x += TEXTFOCUSBORDER ;
234 size.y += 2 * TEXTFOCUSBORDER ;
235 }
236 else
237 {
238 // clipping is too tight
239 size.y += 1 ;
240 }
241 return size;
242}
243
244void wxComboBox::DoMoveWindow(int x, int y, int width, int height)
245{
246 wxControl::DoMoveWindow(x, y, width , height );
247
248 if ( m_text == NULL )
249 {
250 // we might not be fully constructed yet, therefore watch out...
251 if ( m_choice )
252 m_choice->SetSize(0, 0 , width, -1);
253 }
254 else
255 {
256 wxCoord wText = width - m_choice->GetPopupWidth() - MARGIN;
257 m_text->SetSize(TEXTFOCUSBORDER, TEXTFOCUSBORDER, wText, -1 );
258 // put it at an inset of 1 to have outer area shadows drawn as well
259 m_choice->SetSize(TEXTFOCUSBORDER + wText + MARGIN - 1 , TEXTFOCUSBORDER, m_choice->GetPopupWidth() , -1);
260 }
261}
262
263
264
265// ----------------------------------------------------------------------------
266// operations forwarded to the subcontrols
267// ----------------------------------------------------------------------------
268
269bool wxComboBox::Enable(bool enable)
270{
271 if ( !wxControl::Enable(enable) )
272 return FALSE;
273
274 return TRUE;
275}
276
277bool wxComboBox::Show(bool show)
278{
279 if ( !wxControl::Show(show) )
280 return FALSE;
281
282 return TRUE;
283}
284
285void wxComboBox::SetFocus()
286{
287 if ( m_text != NULL) {
288 m_text->SetFocus();
289 }
290}
291
292
293void wxComboBox::DelegateTextChanged( const wxString& value )
294{
295 SetStringSelection( value );
296}
297
298
299void wxComboBox::DelegateChoice( const wxString& value )
300{
301 SetStringSelection( value );
302}
303
304
305bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
306 const wxString& value,
307 const wxPoint& pos,
308 const wxSize& size,
309 const wxArrayString& choices,
310 long style,
311 const wxValidator& validator,
312 const wxString& name)
313{
314 wxCArrayString chs( choices );
315
316 return Create( parent, id, value, pos, size, chs.GetCount(),
317 chs.GetStrings(), style, validator, name );
318}
319
320
321bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
322 const wxString& value,
323 const wxPoint& pos,
324 const wxSize& size,
325 int n, const wxString choices[],
326 long style,
327 const wxValidator& validator,
328 const wxString& name)
329{
330 if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style ,
331 wxDefaultValidator, name) )
332 {
333 return FALSE;
334 }
335
336 m_choice = new wxComboBoxChoice(this, style );
337 wxSize csize = size;
338 if ( style & wxCB_READONLY )
339 {
340 m_text = NULL;
341 }
342 else
343 {
344 m_text = new wxComboBoxText(this);
345 if ( size.y == -1 )
346 {
347 csize.y = m_text->GetSize().y ;
348 csize.y += 2 * TEXTFOCUSBORDER ;
349 }
350 }
351
352 DoSetSize(pos.x, pos.y, csize.x, csize.y);
353
354 for ( int i = 0 ; i < n ; i++ )
355 {
356 m_choice->DoAppend( choices[ i ] );
357 }
358
359 SetBestSize(size); // Needed because it is a wxControlWithItems
360
361 return TRUE;
362}
363
364wxString wxComboBox::GetValue() const
365{
366 wxString result;
367
368 if ( m_text == NULL )
369 {
370 result = m_choice->GetString( m_choice->GetSelection() );
371 }
372 else
373 {
374 result = m_text->GetValue();
375 }
376
377 return result;
378}
379
380int wxComboBox::GetCount() const
381{
382 return m_choice->GetCount() ;
383}
384
385void wxComboBox::SetValue(const wxString& value)
386{
387 if ( HasFlag(wxCB_READONLY) )
388 SetStringSelection( value ) ;
389 else
390 m_text->SetValue( value );
391}
392
393// Clipboard operations
394void wxComboBox::Copy()
395{
396 if ( m_text != NULL )
397 {
398 m_text->Copy();
399 }
400}
401
402void wxComboBox::Cut()
403{
404 if ( m_text != NULL )
405 {
406 m_text->Cut();
407 }
408}
409
410void wxComboBox::Paste()
411{
412 if ( m_text != NULL )
413 {
414 m_text->Paste();
415 }
416}
417
418void wxComboBox::SetEditable(bool editable)
419{
420 if ( ( m_text == NULL ) && editable )
421 {
422 m_text = new wxComboBoxText( this );
423 }
424 else if ( ( m_text != NULL ) && !editable )
425 {
426 delete m_text;
427 m_text = NULL;
428 }
429
430 int currentX, currentY;
431 GetPosition( &currentX, &currentY );
432
433 int currentW, currentH;
434 GetSize( &currentW, &currentH );
435
436 DoMoveWindow( currentX, currentY, currentW, currentH );
437}
438
439void wxComboBox::SetInsertionPoint(long pos)
440{
441 // TODO
442}
443
444void wxComboBox::SetInsertionPointEnd()
445{
446 // TODO
447}
448
449long wxComboBox::GetInsertionPoint() const
450{
451 // TODO
452 return 0;
453}
454
455long wxComboBox::GetLastPosition() const
456{
457 // TODO
458 return 0;
459}
460
461void wxComboBox::Replace(long from, long to, const wxString& value)
462{
463 // TODO
464}
465
466void wxComboBox::Remove(long from, long to)
467{
468 // TODO
469}
470
471void wxComboBox::SetSelection(long from, long to)
472{
473 // TODO
474}
475
476int wxComboBox::DoAppend(const wxString& item)
477{
478 return m_choice->DoAppend( item ) ;
479}
480
481int wxComboBox::DoInsert(const wxString& item, int pos)
482{
483 return m_choice->DoInsert( item , pos ) ;
484}
485
486void wxComboBox::DoSetItemClientData(int n, void* clientData)
487{
488 return m_choice->DoSetItemClientData( n , clientData ) ;
489}
490
491void* wxComboBox::DoGetItemClientData(int n) const
492{
493 return m_choice->DoGetItemClientData( n ) ;
494}
495
496void wxComboBox::DoSetItemClientObject(int n, wxClientData* clientData)
497{
498 return m_choice->DoSetItemClientObject( n , clientData ) ;
499}
500
501wxClientData* wxComboBox::DoGetItemClientObject(int n) const
502{
503 return m_choice->DoGetItemClientObject( n ) ;
504}
505
506void wxComboBox::FreeData()
507{
508 if ( HasClientObjectData() )
509 {
510 size_t count = GetCount();
511 for ( size_t n = 0; n < count; n++ )
512 {
513 SetClientObject( n, NULL );
514 }
515 }
516}
517
518void wxComboBox::Delete(int n)
519{
520 // force client object deletion
521 if( HasClientObjectData() )
522 SetClientObject( n, NULL );
523 m_choice->Delete( n );
524}
525
526void wxComboBox::Clear()
527{
528 FreeData();
529 m_choice->Clear();
530}
531
532int wxComboBox::GetSelection() const
533{
534 return m_choice->GetSelection();
535}
536
537void wxComboBox::SetSelection(int n)
538{
539 m_choice->SetSelection( n );
540
541 if ( m_text != NULL )
542 {
543 m_text->SetValue( GetString( n ) );
544 }
545}
546
547int wxComboBox::FindString(const wxString& s) const
548{
549 return m_choice->FindString( s );
550}
551
552wxString wxComboBox::GetString(int n) const
553{
554 return m_choice->GetString( n );
555}
556
557wxString wxComboBox::GetStringSelection() const
558{
559 int sel = GetSelection ();
560 if (sel > -1)
561 return wxString(this->GetString (sel));
562 else
563 return wxEmptyString;
564}
565
566bool wxComboBox::SetStringSelection(const wxString& sel)
567{
568 int s = FindString (sel);
569 if (s > -1)
570 {
571 SetSelection (s);
572 return TRUE;
573 }
574 else
575 return FALSE;
576}
577
578void wxComboBox::SetString(int n, const wxString& s)
579{
580 m_choice->SetString( n , s ) ;
581}
582
583
584wxInt32 wxComboBox::MacControlHit(WXEVENTHANDLERREF WXUNUSED(handler) , WXEVENTREF WXUNUSED(event) )
585{
586 /* For consistency with other platforms, clicking in the text area does not constitute a selection
587 wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, m_windowId );
588 event.SetInt(GetSelection());
589 event.SetEventObject(this);
590 event.SetString(GetStringSelection());
591 ProcessCommand(event);*/
592 return noErr ;
593}
594