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