Olly Betts' typo patch
[wxWidgets.git] / src / univ / combobox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: univ/combobox.cpp
3 // Purpose: wxComboControl and wxComboBox implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 15.12.00
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "univcombobox.h"
22 #endif
23
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 #if wxUSE_COMBOBOX
31
32 #ifndef WX_PRECOMP
33 #include "wx/log.h"
34
35 #include "wx/button.h"
36 #include "wx/combobox.h"
37 #include "wx/listbox.h"
38 #include "wx/textctrl.h"
39 #include "wx/bmpbuttn.h"
40
41 #include "wx/validate.h"
42 #endif
43
44 #include "wx/tooltip.h"
45 #include "wx/popupwin.h"
46
47 #include "wx/univ/renderer.h"
48 #include "wx/univ/inphand.h"
49 #include "wx/univ/theme.h"
50
51 /*
52 The keyboard event flow:
53
54 1. they always come to the text ctrl
55 2. it forwards the ones it doesn't process to the wxComboControl
56 3. which passes them to the popup window if it is popped up
57 */
58
59 // constants
60 // ----------------------------------------------------------------------------
61
62 // the margin between the text control and the combo button
63 static const wxCoord g_comboMargin = 2;
64
65 // ----------------------------------------------------------------------------
66 // wxComboButton is just a normal button except that it sends commands to the
67 // combobox and not its parent
68 // ----------------------------------------------------------------------------
69
70 class wxComboButton : public wxBitmapButton
71 {
72 public:
73 wxComboButton(wxComboControl *combo)
74 : wxBitmapButton(combo->GetParent(), wxID_ANY, wxNullBitmap,
75 wxDefaultPosition, wxDefaultSize,
76 wxBORDER_NONE | wxBU_EXACTFIT)
77 {
78 m_combo = combo;
79
80 wxBitmap bmpNormal, bmpFocus, bmpPressed, bmpDisabled;
81
82 GetRenderer()->GetComboBitmaps(&bmpNormal,
83 &bmpFocus,
84 &bmpPressed,
85 &bmpDisabled);
86
87 SetBitmapLabel(bmpNormal);
88 SetBitmapFocus(bmpFocus.Ok() ? bmpFocus : bmpNormal);
89 SetBitmapSelected(bmpPressed.Ok() ? bmpPressed : bmpNormal);
90 SetBitmapDisabled(bmpDisabled.Ok() ? bmpDisabled : bmpNormal);
91
92 SetBestSize(wxDefaultSize);
93 }
94
95 protected:
96 void OnButton(wxCommandEvent& WXUNUSED(event)) { m_combo->ShowPopup(); }
97
98 virtual wxSize DoGetBestClientSize() const
99 {
100 const wxBitmap& bmp = GetBitmapLabel();
101
102 return wxSize(bmp.GetWidth(), bmp.GetHeight());
103
104 }
105
106 private:
107 wxComboControl *m_combo;
108
109 DECLARE_EVENT_TABLE()
110 };
111
112 // ----------------------------------------------------------------------------
113 // wxComboListBox is a listbox modified to be used as a popup window in a
114 // combobox
115 // ----------------------------------------------------------------------------
116
117 class wxComboListBox : public wxListBox, public wxComboPopup
118 {
119 public:
120 // ctor and dtor
121 wxComboListBox(wxComboControl *combo, int style = 0);
122 virtual ~wxComboListBox();
123
124 // implement wxComboPopup methods
125 virtual bool SetSelection(const wxString& s);
126 virtual wxControl *GetControl() { return this; }
127 virtual void OnShow();
128 virtual wxCoord GetBestWidth() const;
129
130 // fix virtual function hiding
131 virtual void SetSelection(int n) { DoSetSelection(n, true); }
132 void SetSelection(int n, bool select) { DoSetSelection(n, select); }
133
134 protected:
135 // we shouldn't return height too big from here
136 virtual wxSize DoGetBestClientSize() const;
137
138 // filter mouse move events happening outside the list box
139 void OnMouseMove(wxMouseEvent& event);
140
141 // set m_clicked value from here
142 void OnLeftUp(wxMouseEvent& event);
143
144 // called whenever the user selects or activates a listbox item
145 void OnSelect(wxCommandEvent& event);
146
147 // used to process wxUniv actions
148 bool PerformAction(const wxControlAction& action,
149 long numArg,
150 const wxString& strArg);
151
152 private:
153 // has the mouse been released on this control?
154 bool m_clicked;
155
156 DECLARE_EVENT_TABLE()
157 };
158
159 // ----------------------------------------------------------------------------
160 // wxComboTextCtrl is a simple text ctrl which forwards
161 // wxEVT_COMMAND_TEXT_UPDATED events and all key events to the combobox
162 // ----------------------------------------------------------------------------
163
164 class wxComboTextCtrl : public wxTextCtrl
165 {
166 public:
167 wxComboTextCtrl(wxComboControl *combo,
168 const wxString& value,
169 long style,
170 const wxValidator& validator);
171
172 protected:
173 void OnKey(wxKeyEvent& event);
174 void OnText(wxCommandEvent& event);
175
176 private:
177 wxComboControl *m_combo;
178
179 DECLARE_EVENT_TABLE()
180 };
181
182 // ----------------------------------------------------------------------------
183 // event tables and such
184 // ----------------------------------------------------------------------------
185
186 BEGIN_EVENT_TABLE(wxComboButton, wxButton)
187 EVT_BUTTON(wxID_ANY, wxComboButton::OnButton)
188 END_EVENT_TABLE()
189
190 BEGIN_EVENT_TABLE(wxComboListBox, wxListBox)
191 EVT_LISTBOX(wxID_ANY, wxComboListBox::OnSelect)
192 EVT_LISTBOX_DCLICK(wxID_ANY, wxComboListBox::OnSelect)
193 EVT_MOTION(wxComboListBox::OnMouseMove)
194 EVT_LEFT_UP(wxComboListBox::OnLeftUp)
195 END_EVENT_TABLE()
196
197 BEGIN_EVENT_TABLE(wxComboControl, wxControl)
198 EVT_KEY_DOWN(wxComboControl::OnKey)
199 EVT_KEY_UP(wxComboControl::OnKey)
200 END_EVENT_TABLE()
201
202 BEGIN_EVENT_TABLE(wxComboTextCtrl, wxTextCtrl)
203 EVT_KEY_DOWN(wxComboTextCtrl::OnKey)
204 EVT_KEY_UP(wxComboTextCtrl::OnKey)
205 EVT_TEXT(wxID_ANY, wxComboTextCtrl::OnText)
206 END_EVENT_TABLE()
207
208 IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
209
210 // ============================================================================
211 // implementation
212 // ============================================================================
213
214 // ----------------------------------------------------------------------------
215 // wxComboControl creation
216 // ----------------------------------------------------------------------------
217
218 void wxComboControl::Init()
219 {
220 m_popup = (wxComboPopup *)NULL;
221 m_winPopup = (wxPopupComboWindow *)NULL;
222 m_isPopupShown = false;
223 m_btn = NULL;
224 m_text = NULL;
225 }
226
227 bool wxComboControl::Create(wxWindow *parent,
228 wxWindowID id,
229 const wxString& value,
230 const wxPoint& pos,
231 const wxSize& size,
232 long style,
233 const wxValidator& validator,
234 const wxString& name)
235 {
236 // first create our own window, i.e. the one which will contain all
237 // subcontrols
238 style &= ~wxBORDER_NONE;
239 style |= wxBORDER_SUNKEN;
240 if ( !wxControl::Create(parent, id, pos, size, style, validator, name) )
241 return false;
242
243 // create the text control and the button as our siblings (*not* children),
244 // don't care about size/position here - they will be set in DoMoveWindow()
245 m_btn = new wxComboButton(this);
246 m_text = new wxComboTextCtrl(this,
247 value,
248 style & wxCB_READONLY ? wxTE_READONLY : 0,
249 validator);
250
251 // for compatibility with the other ports, the height specified is the
252 // combined height of the combobox itself and the popup
253 if ( size.y == wxDefaultCoord )
254 {
255 // ok, use default height for popup too
256 m_heightPopup = wxDefaultCoord;
257 }
258 else
259 {
260 m_heightPopup = size.y - DoGetBestSize().y;
261 }
262
263 SetBestSize(size);
264 Move(pos);
265
266 // create the popup window immediately here to allow creating the controls
267 // with parent == GetPopupWindow() from the derived class ctor
268 m_winPopup = new wxPopupComboWindow(this);
269
270 // have to disable this window to avoid interfering it with message
271 // processing to the text and the button... but pretend it is enabled to
272 // make IsEnabled() return true
273 wxControl::Enable(false); // don't use non virtual Disable() here!
274 m_isEnabled = true;
275
276 CreateInputHandler(wxINP_HANDLER_COMBOBOX);
277
278 return true;
279 }
280
281 wxComboControl::~wxComboControl()
282 {
283 // as the button and the text control are the parent's children and not
284 // ours, we have to delete them manually - they are not deleted
285 // automatically by wxWidgets when we're deleted
286 delete m_btn;
287 delete m_text;
288
289 delete m_winPopup;
290 }
291
292 // ----------------------------------------------------------------------------
293 // geometry stuff
294 // ----------------------------------------------------------------------------
295
296 void wxComboControl::DoSetSize(int x, int y,
297 int width, int WXUNUSED(height),
298 int sizeFlags)
299 {
300 // combo height is always fixed
301 wxControl::DoSetSize(x, y, width, DoGetBestSize().y, sizeFlags);
302 }
303
304 wxSize wxComboControl::DoGetBestClientSize() const
305 {
306 wxSize sizeBtn = m_btn->GetBestSize(),
307 sizeText = m_text->GetBestSize();
308 wxCoord widthPopup = 0;
309
310 if (m_popup)
311 {
312 widthPopup = m_popup->GetBestWidth();
313 }
314
315 return wxSize(wxMax(sizeText.x + g_comboMargin + sizeBtn.x, widthPopup),
316 wxMax(sizeBtn.y, sizeText.y));
317 }
318
319 void wxComboControl::DoMoveWindow(int x, int y, int width, int height)
320 {
321 wxControl::DoMoveWindow(x, y, width, height);
322
323 // position the subcontrols inside the client area
324 wxRect rectBorders = GetRenderer()->GetBorderDimensions(GetBorder());
325 x += rectBorders.x;
326 y += rectBorders.y;
327 width -= rectBorders.x + rectBorders.width;
328 height -= rectBorders.y + rectBorders.height;
329
330 wxSize sizeBtn = m_btn->GetBestSize();
331
332 wxCoord wText = width - sizeBtn.x;
333 wxPoint p = GetParent() ? GetParent()->GetClientAreaOrigin() : wxPoint(0,0);
334 m_text->SetSize(x - p.x, y - p.y, wText, height);
335 m_btn->SetSize(x - p.x + wText, y - p.y, sizeBtn.x, height);
336 }
337
338 // ----------------------------------------------------------------------------
339 // operations
340 // ----------------------------------------------------------------------------
341
342 bool wxComboControl::Enable(bool enable)
343 {
344 if ( !wxControl::Enable(enable) )
345 return false;
346
347 m_btn->Enable(enable);
348 m_text->Enable(enable);
349
350 return true;
351 }
352
353 bool wxComboControl::Show(bool show)
354 {
355 if ( !wxControl::Show(show) )
356 return false;
357
358 if (m_btn)
359 m_btn->Show(show);
360
361 if (m_text)
362 m_text->Show(show);
363
364 return true;
365 }
366
367 #if wxUSE_TOOLTIPS
368 void wxComboControl::DoSetToolTip(wxToolTip *tooltip)
369 {
370 wxControl::DoSetToolTip(tooltip);
371
372 // Set tool tip for button and text box
373 if (m_text && m_btn)
374 {
375 if (tooltip)
376 {
377 const wxString &tip = tooltip->GetTip();
378 m_text->SetToolTip(tip);
379 m_btn->SetToolTip(tip);
380 }
381 else
382 {
383 m_text->SetToolTip(NULL);
384 m_btn->SetToolTip(NULL);
385 }
386 }
387 }
388 #endif // wxUSE_TOOLTIPS
389
390 // ----------------------------------------------------------------------------
391 // popup window handling
392 // ----------------------------------------------------------------------------
393
394 void wxComboControl::SetPopupControl(wxComboPopup *popup)
395 {
396 m_popup = popup;
397 }
398
399 void wxComboControl::ShowPopup()
400 {
401 wxCHECK_RET( m_popup, _T("no popup to show in wxComboControl") );
402 wxCHECK_RET( !IsPopupShown(), _T("popup window already shown") );
403
404 wxControl *control = m_popup->GetControl();
405
406 // size and position the popup window correctly
407 m_winPopup->SetSize(GetSize().x,
408 m_heightPopup == wxDefaultCoord ? control->GetBestSize().y
409 : m_heightPopup);
410 wxSize sizePopup = m_winPopup->GetClientSize();
411 control->SetSize(0, 0, sizePopup.x, sizePopup.y);
412
413 // some controls don't accept the size we give then: e.g. a listbox may
414 // require more space to show its last row
415 wxSize sizeReal = control->GetSize();
416 if ( sizeReal != sizePopup )
417 {
418 m_winPopup->SetClientSize(sizeReal);
419 }
420
421 m_winPopup->PositionNearCombo();
422
423 // show it
424 m_popup->OnShow();
425 m_winPopup->Popup(m_text);
426 m_text->SelectAll();
427 m_popup->SetSelection(m_text->GetValue());
428
429 m_isPopupShown = true;
430 }
431
432 void wxComboControl::HidePopup()
433 {
434 wxCHECK_RET( m_popup, _T("no popup to hide in wxComboControl") );
435 wxCHECK_RET( IsPopupShown(), _T("popup window not shown") );
436
437 m_winPopup->Dismiss();
438
439 m_isPopupShown = false;
440 }
441
442 void wxComboControl::OnSelect(const wxString& value)
443 {
444 m_text->SetValue(value);
445 m_text->SelectAll();
446
447 OnDismiss();
448 }
449
450 void wxComboControl::OnDismiss()
451 {
452 HidePopup();
453 m_text->SetFocus();
454 }
455
456 // ----------------------------------------------------------------------------
457 // wxComboTextCtrl
458 // ----------------------------------------------------------------------------
459
460 wxComboTextCtrl::wxComboTextCtrl(wxComboControl *combo,
461 const wxString& value,
462 long style,
463 const wxValidator& validator)
464 : wxTextCtrl(combo->GetParent(), wxID_ANY, value,
465 wxDefaultPosition, wxDefaultSize,
466 wxBORDER_NONE | style,
467 validator)
468 {
469 m_combo = combo;
470 }
471
472 void wxComboTextCtrl::OnText(wxCommandEvent& event)
473 {
474 if ( m_combo->IsPopupShown() )
475 {
476 m_combo->GetPopupControl()->SetSelection(GetValue());
477 }
478
479 // we need to make a copy of the event to have the correct originating
480 // object and id
481 wxCommandEvent event2 = event;
482 event2.SetEventObject(m_combo);
483 event2.SetId(m_combo->GetId());
484
485 // there is a small incompatibility with wxMSW here: the combobox gets the
486 // event before the text control in our case which corresponds to SMW
487 // CBN_EDITUPDATE notification and not CBN_EDITCHANGE one wxMSW currently
488 // uses
489 //
490 // if this is really a problem, we can play games with the event handlers
491 // to circumvent this
492 (void)m_combo->ProcessEvent(event2);
493
494 event.Skip();
495 }
496
497 // pass the keys we don't process to the combo first
498 void wxComboTextCtrl::OnKey(wxKeyEvent& event)
499 {
500 switch ( event.GetKeyCode() )
501 {
502 case WXK_RETURN:
503 // the popup control gets it first but only if it is shown
504 if ( !m_combo->IsPopupShown() )
505 break;
506 //else: fall through
507
508 case WXK_UP:
509 case WXK_DOWN:
510 case WXK_ESCAPE:
511 case WXK_PAGEDOWN:
512 case WXK_PAGEUP:
513 case WXK_PRIOR:
514 case WXK_NEXT:
515 (void)m_combo->ProcessEvent(event);
516 return;
517 }
518
519 event.Skip();
520 }
521
522 // ----------------------------------------------------------------------------
523 // wxComboListBox
524 // ----------------------------------------------------------------------------
525
526 wxComboListBox::wxComboListBox(wxComboControl *combo, int style)
527 : wxListBox(combo->GetPopupWindow(), wxID_ANY,
528 wxDefaultPosition, wxDefaultSize,
529 0, NULL,
530 wxBORDER_SIMPLE | wxLB_INT_HEIGHT | style),
531 wxComboPopup(combo)
532 {
533 // we don't react to the mouse events outside the window at all
534 StopAutoScrolling();
535 }
536
537 wxComboListBox::~wxComboListBox()
538 {
539 }
540
541 bool wxComboListBox::SetSelection(const wxString& value)
542 {
543 // FindItem() would just find the current item for an empty string (it
544 // always matches), but we want to show the first one in such case
545 if ( value.empty() )
546 {
547 if ( GetCount() )
548 {
549 wxListBox::SetSelection(0);
550 }
551 //else: empty listbox - nothing to do
552 }
553 else if ( !FindItem(value) )
554 {
555 // no match att all
556 return false;
557 }
558
559 return true;
560 }
561
562 void wxComboListBox::OnSelect(wxCommandEvent& event)
563 {
564 if ( m_clicked )
565 {
566 // first update the combo and close the listbox
567 m_combo->OnSelect(event.GetString());
568
569 // next let the user code have the event
570
571 // all fields are already filled by the listbox, just change the event
572 // type and send it to the combo
573 wxCommandEvent event2 = event;
574 event2.SetEventType(wxEVT_COMMAND_COMBOBOX_SELECTED);
575 event2.SetEventObject(m_combo);
576 event2.SetId(m_combo->GetId());
577 m_combo->ProcessEvent(event2);
578 }
579 //else: ignore the events resulting from just moving the mouse initially
580 }
581
582 void wxComboListBox::OnShow()
583 {
584 // nobody clicked us yet
585 m_clicked = false;
586 }
587
588 bool wxComboListBox::PerformAction(const wxControlAction& action,
589 long numArg,
590 const wxString& strArg)
591
592 {
593 if ( action == wxACTION_LISTBOX_FIND )
594 {
595 // we don't let the listbox handle this as instead of just using the
596 // single key presses, as usual, we use the text ctrl value as prefix
597 // and this is done by wxComboControl itself
598 return true;
599 }
600
601 return wxListBox::PerformAction(action, numArg, strArg);
602 }
603
604 void wxComboListBox::OnLeftUp(wxMouseEvent& event)
605 {
606 // we should dismiss the combo now
607 m_clicked = true;
608
609 event.Skip();
610 }
611
612 void wxComboListBox::OnMouseMove(wxMouseEvent& event)
613 {
614 // while a wxComboListBox is shown, it always has capture, so if it doesn't
615 // we're about to go away anyhow (normally this shouldn't happen at all,
616 // but I don't put assert here as it just might do on other platforms and
617 // it doesn't break anything anyhow)
618 if ( this == wxWindow::GetCapture() )
619 {
620 if ( HitTest(event.GetPosition()) == wxHT_WINDOW_INSIDE )
621 {
622 event.Skip();
623 }
624 //else: popup shouldn't react to the mouse motions outside it, it only
625 // captures the mouse to be able to detect when it must be
626 // dismissed, so don't call Skip()
627 }
628 }
629
630 wxCoord wxComboListBox::GetBestWidth() const
631 {
632 wxSize size = wxListBox::GetBestSize();
633 return size.x;
634 }
635
636 wxSize wxComboListBox::DoGetBestClientSize() const
637 {
638 // don't return size too big or we risk to not fit on the screen
639 wxSize size = wxListBox::DoGetBestClientSize();
640 wxCoord hChar = GetCharHeight();
641
642 int nLines = size.y / hChar;
643
644 // 10 is the same limit as used by wxMSW
645 if ( nLines > 10 )
646 {
647 size.y = 10*hChar;
648 }
649
650 return size;
651 }
652
653 // ----------------------------------------------------------------------------
654 // wxComboBox
655 // ----------------------------------------------------------------------------
656
657 void wxComboBox::Init()
658 {
659 m_lbox = (wxListBox *)NULL;
660 }
661
662 wxComboBox::wxComboBox(wxWindow *parent,
663 wxWindowID id,
664 const wxString& value,
665 const wxPoint& pos,
666 const wxSize& size,
667 const wxArrayString& choices,
668 long style,
669 const wxValidator& validator,
670 const wxString& name)
671 {
672 Init();
673
674 Create(parent, id, value, pos, size, choices, style, validator, name);
675 }
676
677 bool wxComboBox::Create(wxWindow *parent,
678 wxWindowID id,
679 const wxString& value,
680 const wxPoint& pos,
681 const wxSize& size,
682 const wxArrayString& choices,
683 long style,
684 const wxValidator& validator,
685 const wxString& name)
686 {
687 wxCArrayString chs(choices);
688
689 return Create(parent, id, value, pos, size, chs.GetCount(),
690 chs.GetStrings(), style, validator, name);
691 }
692
693 bool wxComboBox::Create(wxWindow *parent,
694 wxWindowID id,
695 const wxString& value,
696 const wxPoint& pos,
697 const wxSize& size,
698 int n,
699 const wxString choices[],
700 long style,
701 const wxValidator& validator,
702 const wxString& name)
703 {
704 if ( !wxComboControl::Create(parent, id, value, pos, size, style,
705 validator, name) )
706 {
707 return false;
708 }
709
710 wxComboListBox *combolbox =
711 new wxComboListBox(this, style & wxCB_SORT ? wxLB_SORT : 0);
712 m_lbox = combolbox;
713 m_lbox->Set(n, choices);
714
715 SetPopupControl(combolbox);
716
717 return true;
718 }
719
720 wxComboBox::~wxComboBox()
721 {
722 }
723
724 // ----------------------------------------------------------------------------
725 // wxComboBox methods forwarded to wxTextCtrl
726 // ----------------------------------------------------------------------------
727
728 wxString wxComboBox::GetValue() const
729 {
730 return GetText()->GetValue();
731 }
732
733 void wxComboBox::SetValue(const wxString& value)
734 {
735 GetText()->SetValue(value);
736 }
737
738 void wxComboBox::Copy()
739 {
740 GetText()->Copy();
741 }
742
743 void wxComboBox::Cut()
744 {
745 GetText()->Cut();
746 }
747
748 void wxComboBox::Paste()
749 {
750 GetText()->Paste();
751 }
752
753 void wxComboBox::SetInsertionPoint(long pos)
754 {
755 GetText()->SetInsertionPoint(pos);
756 }
757
758 void wxComboBox::SetInsertionPointEnd()
759 {
760 GetText()->SetInsertionPointEnd();
761 }
762
763 long wxComboBox::GetInsertionPoint() const
764 {
765 return GetText()->GetInsertionPoint();
766 }
767
768 wxTextPos wxComboBox::GetLastPosition() const
769 {
770 return GetText()->GetLastPosition();
771 }
772
773 void wxComboBox::Replace(long from, long to, const wxString& value)
774 {
775 GetText()->Replace(from, to, value);
776 }
777
778 void wxComboBox::Remove(long from, long to)
779 {
780 GetText()->Remove(from, to);
781 }
782
783 void wxComboBox::SetSelection(long from, long to)
784 {
785 GetText()->SetSelection(from, to);
786 }
787
788 void wxComboBox::SetEditable(bool editable)
789 {
790 GetText()->SetEditable(editable);
791 }
792
793 // ----------------------------------------------------------------------------
794 // wxComboBox methods forwarded to wxListBox
795 // ----------------------------------------------------------------------------
796
797 void wxComboBox::Clear()
798 {
799 GetLBox()->Clear();
800 GetText()->SetValue(wxEmptyString);
801 }
802
803 void wxComboBox::Delete(int n)
804 {
805 wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::Delete") );
806
807 if (GetSelection() == n)
808 GetText()->SetValue(wxEmptyString);
809
810 GetLBox()->Delete(n);
811 }
812
813 int wxComboBox::GetCount() const
814 {
815 return GetLBox()->GetCount();
816 }
817
818 wxString wxComboBox::GetString(int n) const
819 {
820 wxCHECK_MSG( (n >= 0) && (n < GetCount()), wxEmptyString, _T("invalid index in wxComboBox::GetString") );
821
822 return GetLBox()->GetString(n);
823 }
824
825 void wxComboBox::SetString(int n, const wxString& s)
826 {
827 wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::SetString") );
828
829 GetLBox()->SetString(n, s);
830 }
831
832 int wxComboBox::FindString(const wxString& s) const
833 {
834 return GetLBox()->FindString(s);
835 }
836
837 void wxComboBox::SetSelection(int n)
838 {
839 wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::Select") );
840
841 GetLBox()->SetSelection(n);
842 GetText()->SetValue(GetLBox()->GetString(n));
843 }
844
845 int wxComboBox::GetSelection() const
846 {
847 #if 1 // FIXME:: What is the correct behavior?
848 // if the current value isn't one of the listbox strings, return -1
849 return GetLBox()->GetSelection();
850 #else
851 // Why oh why is this done this way?
852 // It is not because the value displayed in the text can be found
853 // in the list that it is the item that is selected!
854 return FindString(GetText()->GetValue());
855 #endif
856 }
857
858 int wxComboBox::DoAppend(const wxString& item)
859 {
860 return GetLBox()->Append(item);
861 }
862
863 int wxComboBox::DoInsert(const wxString& item, int pos)
864 {
865 wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list"));
866 wxCHECK_MSG((pos>=0) && (pos<=GetCount()), -1, wxT("invalid index"));
867
868 if (pos == GetCount())
869 return DoAppend(item);
870
871 GetLBox()->Insert(item, pos);
872 return pos;
873 }
874
875 void wxComboBox::DoSetItemClientData(int n, void* clientData)
876 {
877 GetLBox()->SetClientData(n, clientData);
878 }
879
880 void *wxComboBox::DoGetItemClientData(int n) const
881 {
882 return GetLBox()->GetClientData(n);
883 }
884
885 void wxComboBox::DoSetItemClientObject(int n, wxClientData* clientData)
886 {
887 GetLBox()->SetClientObject(n, clientData);
888 }
889
890 wxClientData* wxComboBox::DoGetItemClientObject(int n) const
891 {
892 return GetLBox()->GetClientObject(n);
893 }
894
895 bool wxComboBox::IsEditable() const
896 {
897 return GetText() != NULL && (!HasFlag(wxCB_READONLY) || GetText()->IsEditable());
898 }
899
900 void wxComboBox::Undo()
901 {
902 if (IsEditable())
903 GetText()->Undo();
904 }
905
906 void wxComboBox::Redo()
907 {
908 if (IsEditable())
909 GetText()->Redo();
910 }
911
912 void wxComboBox::SelectAll()
913 {
914 GetText()->SelectAll();
915 }
916
917 bool wxComboBox::CanCopy() const
918 {
919 if (GetText() != NULL)
920 return GetText()->CanCopy();
921 else
922 return false;
923 }
924
925 bool wxComboBox::CanCut() const
926 {
927 if (GetText() != NULL)
928 return GetText()->CanCut();
929 else
930 return false;
931 }
932
933 bool wxComboBox::CanPaste() const
934 {
935 if (IsEditable())
936 return GetText()->CanPaste();
937 else
938 return false;
939 }
940
941 bool wxComboBox::CanUndo() const
942 {
943 if (IsEditable())
944 return GetText()->CanUndo();
945 else
946 return false;
947 }
948
949 bool wxComboBox::CanRedo() const
950 {
951 if (IsEditable())
952 return GetText()->CanRedo();
953 else
954 return false;
955 }
956
957
958 // ----------------------------------------------------------------------------
959 // input handling
960 // ----------------------------------------------------------------------------
961
962 void wxComboControl::OnKey(wxKeyEvent& event)
963 {
964 if ( m_isPopupShown )
965 {
966 // pass it to the popped up control
967 (void)m_popup->GetControl()->ProcessEvent(event);
968 }
969 else // no popup
970 {
971 event.Skip();
972 }
973 }
974
975 bool wxComboControl::PerformAction(const wxControlAction& action,
976 long numArg,
977 const wxString& strArg)
978 {
979 bool processed = false;
980 if ( action == wxACTION_COMBOBOX_POPUP )
981 {
982 if ( !m_isPopupShown )
983 {
984 ShowPopup();
985
986 processed = true;
987 }
988 }
989 else if ( action == wxACTION_COMBOBOX_DISMISS )
990 {
991 if ( m_isPopupShown )
992 {
993 HidePopup();
994
995 processed = true;
996 }
997 }
998
999 if ( !processed )
1000 {
1001 // pass along
1002 return wxControl::PerformAction(action, numArg, strArg);
1003 }
1004
1005 return true;
1006 }
1007
1008 // ----------------------------------------------------------------------------
1009 // wxStdComboBoxInputHandler
1010 // ----------------------------------------------------------------------------
1011
1012 wxStdComboBoxInputHandler::wxStdComboBoxInputHandler(wxInputHandler *inphand)
1013 : wxStdInputHandler(inphand)
1014 {
1015 }
1016
1017 bool wxStdComboBoxInputHandler::HandleKey(wxInputConsumer *consumer,
1018 const wxKeyEvent& event,
1019 bool pressed)
1020 {
1021 if ( pressed )
1022 {
1023 wxControlAction action;
1024 switch ( event.GetKeyCode() )
1025 {
1026 case WXK_DOWN:
1027 action = wxACTION_COMBOBOX_POPUP;
1028 break;
1029
1030 case WXK_ESCAPE:
1031 action = wxACTION_COMBOBOX_DISMISS;
1032 break;
1033 }
1034
1035 if ( !action.IsEmpty() )
1036 {
1037 consumer->PerformAction(action);
1038
1039 return true;
1040 }
1041 }
1042
1043 return wxStdInputHandler::HandleKey(consumer, event, pressed);
1044 }
1045
1046 #endif // wxUSE_COMBOBOX