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