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