]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/mac/carbon/combobox.cpp
new renderer architecture
[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 m_container.SetContainerWindow(this);
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 SetBestSize(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 // TODO
472}
473
474void wxComboBox::SetInsertionPointEnd()
475{
476 // TODO
477}
478
479long wxComboBox::GetInsertionPoint() const
480{
481 // TODO
482 return 0;
483}
484
485wxTextPos wxComboBox::GetLastPosition() const
486{
487 // TODO
488 return 0;
489}
490
491void wxComboBox::Replace(long from, long to, const wxString& value)
492{
493 // TODO
494}
495
496void wxComboBox::Remove(long from, long to)
497{
498 // TODO
499}
500
501void wxComboBox::SetSelection(long from, long to)
502{
503 // TODO
504}
505
506int wxComboBox::DoAppend(const wxString& item)
507{
508 return m_choice->DoAppend( item ) ;
509}
510
511int wxComboBox::DoInsert(const wxString& item, unsigned int pos)
512{
513 return m_choice->DoInsert( item , pos ) ;
514}
515
516void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
517{
518 return m_choice->DoSetItemClientData( n , clientData ) ;
519}
520
521void* wxComboBox::DoGetItemClientData(unsigned int n) const
522{
523 return m_choice->DoGetItemClientData( n ) ;
524}
525
526void wxComboBox::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
527{
528 return m_choice->DoSetItemClientObject(n, clientData);
529}
530
531wxClientData* wxComboBox::DoGetItemClientObject(unsigned int n) const
532{
533 return m_choice->DoGetItemClientObject( n ) ;
534}
535
536void wxComboBox::FreeData()
537{
538 if ( HasClientObjectData() )
539 {
540 unsigned int count = GetCount();
541 for ( unsigned int n = 0; n < count; n++ )
542 {
543 SetClientObject( n, NULL );
544 }
545 }
546}
547
548void wxComboBox::Delete(unsigned int n)
549{
550 // force client object deletion
551 if( HasClientObjectData() )
552 SetClientObject( n, NULL );
553 m_choice->Delete( n );
554}
555
556void wxComboBox::Clear()
557{
558 FreeData();
559 m_choice->Clear();
560}
561
562int wxComboBox::GetSelection() const
563{
564 return m_choice->GetSelection();
565}
566
567void wxComboBox::SetSelection(int n)
568{
569 m_choice->SetSelection( n );
570
571 if ( m_text != NULL )
572 m_text->SetValue(GetString(n));
573}
574
575int wxComboBox::FindString(const wxString& s, bool bCase) const
576{
577 return m_choice->FindString( s, bCase );
578}
579
580wxString wxComboBox::GetString(unsigned int n) const
581{
582 return m_choice->GetString( n );
583}
584
585wxString wxComboBox::GetStringSelection() const
586{
587 int sel = GetSelection();
588 if (sel != wxNOT_FOUND)
589 return wxString(this->GetString((unsigned int)sel));
590 else
591 return wxEmptyString;
592}
593
594void wxComboBox::SetString(unsigned int n, const wxString& s)
595{
596 m_choice->SetString( n , s );
597}
598
599bool wxComboBox::IsEditable() const
600{
601 return m_text != NULL && !HasFlag(wxCB_READONLY);
602}
603
604void wxComboBox::Undo()
605{
606 if (m_text != NULL)
607 m_text->Undo();
608}
609
610void wxComboBox::Redo()
611{
612 if (m_text != NULL)
613 m_text->Redo();
614}
615
616void wxComboBox::SelectAll()
617{
618 if (m_text != NULL)
619 m_text->SelectAll();
620}
621
622bool wxComboBox::CanCopy() const
623{
624 if (m_text != NULL)
625 return m_text->CanCopy();
626 else
627 return false;
628}
629
630bool wxComboBox::CanCut() const
631{
632 if (m_text != NULL)
633 return m_text->CanCut();
634 else
635 return false;
636}
637
638bool wxComboBox::CanPaste() const
639{
640 if (m_text != NULL)
641 return m_text->CanPaste();
642 else
643 return false;
644}
645
646bool wxComboBox::CanUndo() const
647{
648 if (m_text != NULL)
649 return m_text->CanUndo();
650 else
651 return false;
652}
653
654bool wxComboBox::CanRedo() const
655{
656 if (m_text != NULL)
657 return m_text->CanRedo();
658 else
659 return false;
660}
661
662wxInt32 wxComboBox::MacControlHit( WXEVENTHANDLERREF WXUNUSED(handler) , WXEVENTREF WXUNUSED(event) )
663{
664/*
665 For consistency with other platforms, clicking in the text area does not constitute a selection
666 wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, m_windowId );
667 event.SetInt(GetSelection());
668 event.SetEventObject(this);
669 event.SetString(GetStringSelection());
670 ProcessCommand(event);
671*/
672
673 return noErr ;
674}
675
676#endif // wxUSE_COMBOBOX