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