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