]> git.saurik.com Git - wxWidgets.git/blame - src/univ/combobox.cpp
concentrating content and structure region calculations
[wxWidgets.git] / src / univ / combobox.cpp
CommitLineData
1e6feb95
VZ
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$
442b35b5 8// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
1e6feb95
VZ
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
1e6feb95
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
a3870b2f 21 #pragma implementation "univcombobox.h"
1e6feb95
VZ
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"
8cb172b4 39 #include "wx/bmpbuttn.h"
1e6feb95
VZ
40
41 #include "wx/validate.h"
42#endif
43
d4e5272b 44#include "wx/tooltip.h"
1e6feb95
VZ
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
1b489359
JS
59// constants
60// ----------------------------------------------------------------------------
61
62// the margin between the text control and the combo button
63static const wxCoord g_comboMargin = 2;
64
1e6feb95
VZ
65// ----------------------------------------------------------------------------
66// wxComboButton is just a normal button except that it sends commands to the
67// combobox and not its parent
68// ----------------------------------------------------------------------------
69
70class wxComboButton : public wxBitmapButton
71{
72public:
73 wxComboButton(wxComboControl *combo)
74 : wxBitmapButton(combo->GetParent(), -1, wxNullBitmap,
75 wxDefaultPosition, wxDefaultSize,
e4606ed9 76 wxBORDER_NONE | wxBU_EXACTFIT)
1e6feb95
VZ
77 {
78 m_combo = combo;
79
e4606ed9
VZ
80 wxBitmap bmpNormal, bmpFocus, bmpPressed, bmpDisabled;
81
82 GetRenderer()->GetComboBitmaps(&bmpNormal,
83 &bmpFocus,
84 &bmpPressed,
85 &bmpDisabled);
1e6feb95 86
1e6feb95 87 SetBitmapLabel(bmpNormal);
e4606ed9
VZ
88 SetBitmapFocus(bmpFocus.Ok() ? bmpFocus : bmpNormal);
89 SetBitmapSelected(bmpPressed.Ok() ? bmpPressed : bmpNormal);
90 SetBitmapDisabled(bmpDisabled.Ok() ? bmpDisabled : bmpNormal);
1e6feb95 91
e4606ed9 92 SetBestSize(wxDefaultSize);
1e6feb95
VZ
93 }
94
95protected:
61fef19b 96 void OnButton(wxCommandEvent& WXUNUSED(event)) { m_combo->ShowPopup(); }
1e6feb95 97
e4606ed9
VZ
98 virtual wxSize DoGetBestClientSize() const
99 {
100 const wxBitmap& bmp = GetBitmapLabel();
101
102 return wxSize(bmp.GetWidth(), bmp.GetHeight());
103
104 }
1e6feb95
VZ
105
106private:
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
117class wxComboListBox : public wxListBox, public wxComboPopup
118{
119public:
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);
8a39593e
JS
126 virtual void SetSelection(int n, bool select)
127 { wxListBox::SetSelection( n, select); };
1e6feb95
VZ
128 virtual wxControl *GetControl() { return this; }
129 virtual void OnShow();
c18670e4 130 virtual wxCoord GetBestWidth() const;
1e6feb95
VZ
131
132protected:
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
55f095d4
VZ
139 // set m_clicked value from here
140 void OnLeftUp(wxMouseEvent& event);
141
1e6feb95
VZ
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
150private:
55f095d4
VZ
151 // has the mouse been released on this control?
152 bool m_clicked;
153
1e6feb95
VZ
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
162class wxComboTextCtrl : public wxTextCtrl
163{
164public:
165 wxComboTextCtrl(wxComboControl *combo,
166 const wxString& value,
167 long style,
168 const wxValidator& validator);
169
170protected:
171 void OnKey(wxKeyEvent& event);
172 void OnText(wxCommandEvent& event);
173
174private:
175 wxComboControl *m_combo;
176
177 DECLARE_EVENT_TABLE()
178};
179
180// ----------------------------------------------------------------------------
181// event tables and such
182// ----------------------------------------------------------------------------
183
184BEGIN_EVENT_TABLE(wxComboButton, wxButton)
185 EVT_BUTTON(-1, wxComboButton::OnButton)
186END_EVENT_TABLE()
187
188BEGIN_EVENT_TABLE(wxComboListBox, wxListBox)
189 EVT_LISTBOX(-1, wxComboListBox::OnSelect)
190 EVT_LISTBOX_DCLICK(-1, wxComboListBox::OnSelect)
191 EVT_MOTION(wxComboListBox::OnMouseMove)
55f095d4 192 EVT_LEFT_UP(wxComboListBox::OnLeftUp)
1e6feb95
VZ
193END_EVENT_TABLE()
194
195BEGIN_EVENT_TABLE(wxComboControl, wxControl)
196 EVT_KEY_DOWN(wxComboControl::OnKey)
197 EVT_KEY_UP(wxComboControl::OnKey)
198END_EVENT_TABLE()
199
200BEGIN_EVENT_TABLE(wxComboTextCtrl, wxTextCtrl)
201 EVT_KEY_DOWN(wxComboTextCtrl::OnKey)
202 EVT_KEY_UP(wxComboTextCtrl::OnKey)
203 EVT_TEXT(-1, wxComboTextCtrl::OnText)
204END_EVENT_TABLE()
205
4e352a3f 206IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
1e6feb95
VZ
207
208// ============================================================================
209// implementation
210// ============================================================================
211
212// ----------------------------------------------------------------------------
213// wxComboControl creation
214// ----------------------------------------------------------------------------
215
216void wxComboControl::Init()
217{
218 m_popup = (wxComboPopup *)NULL;
219 m_winPopup = (wxPopupComboWindow *)NULL;
220 m_isPopupShown = FALSE;
9f41d601
RR
221 m_btn = NULL;
222 m_text = NULL;
1e6feb95
VZ
223}
224
225bool 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 == -1 )
252 {
253 // ok, use default height for popup too
254 m_heightPopup = -1;
255 }
256 else
257 {
258 m_heightPopup = size.y - DoGetBestSize().y;
259 }
260
e4606ed9
VZ
261 SetBestSize(size);
262 Move(pos);
1e6feb95
VZ
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
279wxComboControl::~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 wxWindows 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
294void wxComboControl::DoSetSize(int x, int y,
61fef19b 295 int width, int WXUNUSED(height),
1e6feb95
VZ
296 int sizeFlags)
297{
298 // combo height is always fixed
299 wxControl::DoSetSize(x, y, width, DoGetBestSize().y, sizeFlags);
300}
301
302wxSize wxComboControl::DoGetBestClientSize() const
303{
304 wxSize sizeBtn = m_btn->GetBestSize(),
305 sizeText = m_text->GetBestSize();
e2ca829e 306 wxCoord widthPopup = 0;
1e6feb95 307
e2ca829e
JS
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));
1e6feb95
VZ
315}
316
317void 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
e4606ed9 328 wxSize sizeBtn = m_btn->GetBestSize();
1e6feb95
VZ
329
330 wxCoord wText = width - sizeBtn.x;
c2ef70ec
VS
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);
1e6feb95
VZ
334}
335
336// ----------------------------------------------------------------------------
337// operations
338// ----------------------------------------------------------------------------
339
340bool 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
351bool wxComboControl::Show(bool show)
352{
353 if ( !wxControl::Show(show) )
354 return FALSE;
355
9f41d601
RR
356 if (m_btn)
357 m_btn->Show(show);
55f095d4 358
9f41d601
RR
359 if (m_text)
360 m_text->Show(show);
1e6feb95
VZ
361
362 return TRUE;
363}
364
d4e5272b
JS
365#if wxUSE_TOOLTIPS
366void 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
1e6feb95
VZ
388// ----------------------------------------------------------------------------
389// popup window handling
390// ----------------------------------------------------------------------------
391
392void wxComboControl::SetPopupControl(wxComboPopup *popup)
393{
394 m_popup = popup;
395}
396
397void 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 == -1 ? 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
55f095d4 422 m_popup->OnShow();
1e6feb95
VZ
423 m_winPopup->Popup(m_text);
424 m_text->SelectAll();
425 m_popup->SetSelection(m_text->GetValue());
426
427 m_isPopupShown = TRUE;
428}
429
430void 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
440void wxComboControl::OnSelect(const wxString& value)
441{
442 m_text->SetValue(value);
443 m_text->SelectAll();
444
445 OnDismiss();
446}
447
448void wxComboControl::OnDismiss()
449{
450 HidePopup();
451 m_text->SetFocus();
452}
453
454// ----------------------------------------------------------------------------
455// wxComboTextCtrl
456// ----------------------------------------------------------------------------
457
458wxComboTextCtrl::wxComboTextCtrl(wxComboControl *combo,
459 const wxString& value,
460 long style,
461 const wxValidator& validator)
462 : wxTextCtrl(combo->GetParent(), -1, value,
463 wxDefaultPosition, wxDefaultSize,
464 wxBORDER_NONE | style,
465 validator)
466{
467 m_combo = combo;
468}
469
470void 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
496void 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
524wxComboListBox::wxComboListBox(wxComboControl *combo, int style)
525 : wxListBox(combo->GetPopupWindow(), -1,
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
535wxComboListBox::~wxComboListBox()
536{
537}
538
539bool 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
560void wxComboListBox::OnSelect(wxCommandEvent& event)
561{
55f095d4
VZ
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
1e6feb95
VZ
578}
579
580void wxComboListBox::OnShow()
581{
55f095d4
VZ
582 // nobody clicked us yet
583 m_clicked = FALSE;
1e6feb95
VZ
584}
585
586bool 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
55f095d4
VZ
602void wxComboListBox::OnLeftUp(wxMouseEvent& event)
603{
604 // we should dismiss the combo now
605 m_clicked = TRUE;
606
607 event.Skip();
608}
609
1e6feb95
VZ
610void 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
e2ca829e
JS
628wxCoord wxComboListBox::GetBestWidth() const
629{
630 wxSize size = wxListBox::GetBestSize();
631 return size.x;
632}
633
1e6feb95
VZ
634wxSize 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
655void wxComboBox::Init()
656{
657 m_lbox = (wxListBox *)NULL;
658}
659
584ad2a3
MB
660wxComboBox::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
675bool 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
1e6feb95
VZ
691bool wxComboBox::Create(wxWindow *parent,
692 wxWindowID id,
693 const wxString& value,
694 const wxPoint& pos,
695 const wxSize& size,
696 int n,
ba1e9d6c 697 const wxString choices[],
1e6feb95
VZ
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
718wxComboBox::~wxComboBox()
719{
720}
721
722// ----------------------------------------------------------------------------
723// wxComboBox methods forwarded to wxTextCtrl
724// ----------------------------------------------------------------------------
725
726wxString wxComboBox::GetValue() const
727{
728 return GetText()->GetValue();
729}
730
731void wxComboBox::SetValue(const wxString& value)
732{
733 GetText()->SetValue(value);
734}
735
736void wxComboBox::Copy()
737{
738 GetText()->Copy();
739}
740
741void wxComboBox::Cut()
742{
743 GetText()->Cut();
744}
745
746void wxComboBox::Paste()
747{
748 GetText()->Paste();
749}
750
751void wxComboBox::SetInsertionPoint(long pos)
752{
753 GetText()->SetInsertionPoint(pos);
754}
755
756void wxComboBox::SetInsertionPointEnd()
757{
758 GetText()->SetInsertionPointEnd();
759}
760
761long wxComboBox::GetInsertionPoint() const
762{
763 return GetText()->GetInsertionPoint();
764}
765
766long wxComboBox::GetLastPosition() const
767{
768 return GetText()->GetLastPosition();
769}
770
771void wxComboBox::Replace(long from, long to, const wxString& value)
772{
773 GetText()->Replace(from, to, value);
774}
775
776void wxComboBox::Remove(long from, long to)
777{
778 GetText()->Remove(from, to);
779}
780
781void wxComboBox::SetSelection(long from, long to)
782{
783 GetText()->SetSelection(from, to);
784}
785
786void wxComboBox::SetEditable(bool editable)
787{
788 GetText()->SetEditable(editable);
789}
790
791// ----------------------------------------------------------------------------
792// wxComboBox methods forwarded to wxListBox
793// ----------------------------------------------------------------------------
794
795void wxComboBox::Clear()
796{
797 GetLBox()->Clear();
48aa18c0 798 GetText()->SetValue(wxEmptyString);
1e6feb95
VZ
799}
800
801void wxComboBox::Delete(int n)
802{
48aa18c0
JS
803 wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::Delete") );
804
805 if (GetSelection() == n)
806 GetText()->SetValue(wxEmptyString);
807
1e6feb95
VZ
808 GetLBox()->Delete(n);
809}
810
811int wxComboBox::GetCount() const
812{
813 return GetLBox()->GetCount();
814}
815
816wxString wxComboBox::GetString(int n) const
817{
48aa18c0
JS
818 wxCHECK_MSG( (n >= 0) && (n < GetCount()), wxEmptyString, _T("invalid index in wxComboBox::GetString") );
819
1e6feb95
VZ
820 return GetLBox()->GetString(n);
821}
822
823void wxComboBox::SetString(int n, const wxString& s)
824{
48aa18c0
JS
825 wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::SetString") );
826
1e6feb95
VZ
827 GetLBox()->SetString(n, s);
828}
829
830int wxComboBox::FindString(const wxString& s) const
831{
832 return GetLBox()->FindString(s);
833}
834
835void wxComboBox::Select(int n)
836{
48aa18c0 837 wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::Select") );
1e6feb95
VZ
838
839 GetLBox()->SetSelection(n);
840 GetText()->SetValue(GetLBox()->GetString(n));
841}
842
843int wxComboBox::GetSelection() const
844{
48aa18c0 845#if 1 // FIXME:: What is the correct behavior?
1e6feb95 846 // if the current value isn't one of the listbox strings, return -1
48aa18c0
JS
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!
1e6feb95 852 return FindString(GetText()->GetValue());
48aa18c0 853#endif
1e6feb95
VZ
854}
855
856int wxComboBox::DoAppend(const wxString& item)
857{
858 return GetLBox()->Append(item);
859}
860
243dbf1a
VZ
861int 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
3f85391e 869 GetLBox()->Insert(item, pos);
243dbf1a
VZ
870 return pos;
871}
872
1e6feb95
VZ
873void wxComboBox::DoSetItemClientData(int n, void* clientData)
874{
875 GetLBox()->SetClientData(n, clientData);
876}
877
878void *wxComboBox::DoGetItemClientData(int n) const
879{
880 return GetLBox()->GetClientData(n);
881}
882
883void wxComboBox::DoSetItemClientObject(int n, wxClientData* clientData)
884{
885 GetLBox()->SetClientObject(n, clientData);
886}
887
888wxClientData* wxComboBox::DoGetItemClientObject(int n) const
889{
890 return GetLBox()->GetClientObject(n);
891}
892
893// ----------------------------------------------------------------------------
894// input handling
895// ----------------------------------------------------------------------------
896
2e9f62da 897void wxComboControl::OnKey(wxKeyEvent& event)
1e6feb95
VZ
898{
899 if ( m_isPopupShown )
900 {
901 // pass it to the popped up control
902 (void)m_popup->GetControl()->ProcessEvent(event);
903 }
904 else // no popup
905 {
906 event.Skip();
907 }
908}
909
910bool wxComboControl::PerformAction(const wxControlAction& action,
911 long numArg,
912 const wxString& strArg)
913{
914 bool processed = FALSE;
915 if ( action == wxACTION_COMBOBOX_POPUP )
916 {
917 if ( !m_isPopupShown )
918 {
919 ShowPopup();
920
921 processed = TRUE;
922 }
923 }
924 else if ( action == wxACTION_COMBOBOX_DISMISS )
925 {
926 if ( m_isPopupShown )
927 {
928 HidePopup();
929
930 processed = TRUE;
931 }
932 }
933
934 if ( !processed )
935 {
936 // pass along
937 return wxControl::PerformAction(action, numArg, strArg);
938 }
939
940 return TRUE;
941}
942
943// ----------------------------------------------------------------------------
944// wxStdComboBoxInputHandler
945// ----------------------------------------------------------------------------
946
947wxStdComboBoxInputHandler::wxStdComboBoxInputHandler(wxInputHandler *inphand)
948 : wxStdInputHandler(inphand)
949{
950}
951
23645bfa 952bool wxStdComboBoxInputHandler::HandleKey(wxInputConsumer *consumer,
1e6feb95
VZ
953 const wxKeyEvent& event,
954 bool pressed)
955{
956 if ( pressed )
957 {
958 wxControlAction action;
959 switch ( event.GetKeyCode() )
960 {
961 case WXK_DOWN:
962 action = wxACTION_COMBOBOX_POPUP;
963 break;
964
965 case WXK_ESCAPE:
966 action = wxACTION_COMBOBOX_DISMISS;
967 break;
968 }
969
970 if ( !!action )
971 {
23645bfa 972 consumer->PerformAction(action);
1e6feb95
VZ
973
974 return TRUE;
975 }
976 }
977
23645bfa 978 return wxStdInputHandler::HandleKey(consumer, event, pressed);
1e6feb95
VZ
979}
980
981#endif // wxUSE_COMBOBOX