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