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