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