]> git.saurik.com Git - wxWidgets.git/blob - src/univ/combobox.cpp
guard with compile-time checks the new GDK_* event type symbols; explain why runtime...
[wxWidgets.git] / src / univ / combobox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/univ/combobox.cpp
3 // Purpose:     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 #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"
35     #include "wx/bmpbuttn.h"
36
37     #include "wx/validate.h"
38 #endif
39
40 #include "wx/tooltip.h"
41 #include "wx/combo.h"
42
43 #include "wx/univ/renderer.h"
44 #include "wx/univ/inphand.h"
45 #include "wx/univ/theme.h"
46
47 // ----------------------------------------------------------------------------
48 // wxStdComboBoxInputHandler: allows the user to open/close the combo from kbd
49 // ----------------------------------------------------------------------------
50
51 class WXDLLEXPORT wxStdComboBoxInputHandler : public wxStdInputHandler
52 {
53 public:
54     wxStdComboBoxInputHandler(wxInputHandler *inphand);
55
56     virtual bool HandleKey(wxInputConsumer *consumer,
57                            const wxKeyEvent& event,
58                            bool pressed);
59 };
60
61 // ----------------------------------------------------------------------------
62 // wxComboListBox is a listbox modified to be used as a popup window in a
63 // combobox
64 // ----------------------------------------------------------------------------
65
66 class wxComboListBox : public wxListBox, public wxComboPopup
67 {
68 public:
69     // ctor and dtor
70     wxComboListBox();
71     virtual ~wxComboListBox();
72
73     // implement wxComboPopup methods
74     virtual bool Create(wxWindow* parent);
75     virtual void SetStringValue(const wxString& s);
76     virtual wxString GetStringValue() const;
77     virtual wxWindow *GetControl() { return this; }
78     virtual void OnPopup();
79     virtual wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight);
80
81     // fix virtual function hiding
82     virtual void SetSelection(int n) { DoSetSelection(n, true); }
83     void SetSelection(int n, bool select) { DoSetSelection(n, select); }
84
85     // used to process wxUniv actions
86     bool PerformAction(const wxControlAction& action,
87                        long numArg,
88                        const wxString& strArg);
89
90 protected:
91     // set m_clicked value from here
92     void OnLeftUp(wxMouseEvent& event);
93
94 private:
95     friend class wxComboBox; // it accesses our DoGetItemClientData()
96
97     DECLARE_EVENT_TABLE()
98 };
99
100 // ----------------------------------------------------------------------------
101 // event tables and such
102 // ----------------------------------------------------------------------------
103
104 BEGIN_EVENT_TABLE(wxComboListBox, wxListBox)
105     EVT_LEFT_UP(wxComboListBox::OnLeftUp)
106 END_EVENT_TABLE()
107
108 IMPLEMENT_DYNAMIC_CLASS2(wxComboBox, wxControl, wxComboCtrl)
109
110 // ============================================================================
111 // implementation
112 // ============================================================================
113
114 // ----------------------------------------------------------------------------
115 // wxComboListBox
116 // ----------------------------------------------------------------------------
117
118 wxComboListBox::wxComboListBox() : wxListBox(), wxComboPopup()
119 {
120 }
121
122 bool wxComboListBox::Create(wxWindow* parent)
123 {
124     if ( !wxListBox::Create(parent, wxID_ANY,
125                             wxDefaultPosition, wxDefaultSize,
126                             0, NULL,
127                             wxBORDER_SIMPLE |
128                             ( m_combo->GetWindowStyle() & wxCB_SORT ? wxLB_SORT : 0 ) ) )
129         return false;
130
131     // we don't react to the mouse events outside the window at all
132     StopAutoScrolling();
133
134     return true;
135 }
136
137 wxComboListBox::~wxComboListBox()
138 {
139 }
140
141 wxString wxComboListBox::GetStringValue() const
142 {
143     return wxListBox::GetStringSelection();
144 }
145
146 void wxComboListBox::SetStringValue(const wxString& value)
147 {
148     if ( !value.empty() )
149     {
150         if (FindString(value) != wxNOT_FOUND)
151             wxListBox::SetStringSelection(value);
152     }
153     else
154         wxListBox::SetSelection(-1);
155 }
156
157 void wxComboListBox::OnPopup()
158 {
159 }
160
161 bool wxComboListBox::PerformAction(const wxControlAction& action,
162                                    long numArg,
163                                    const wxString& strArg)
164
165 {
166     if ( action == wxACTION_LISTBOX_FIND )
167     {
168         // we don't let the listbox handle this as instead of just using the
169         // single key presses, as usual, we use the text ctrl value as prefix
170         // and this is done by wxComboCtrl itself
171         return true;
172     }
173
174     return wxListBox::PerformAction(action, numArg, strArg);
175 }
176
177 void wxComboListBox::OnLeftUp(wxMouseEvent& event)
178 {
179     // we should dismiss the combo now
180     // first update the combo and close the listbox
181     Dismiss();
182     m_combo->SetValue(wxListBox::GetStringSelection());
183
184     // next let the user code have the event
185     wxCommandEvent evt(wxEVT_COMMAND_COMBOBOX_SELECTED,m_combo->GetId());
186     evt.SetInt(wxListBox::GetSelection());
187     evt.SetEventObject(m_combo);
188     m_combo->ProcessWindowEvent(evt);
189
190     event.Skip();
191 }
192
193 wxSize wxComboListBox::GetAdjustedSize(int minWidth,
194                                        int WXUNUSED(prefHeight),
195                                        int maxHeight)
196 {
197     wxSize bestSize = wxListBox::GetBestSize();
198     return wxSize(wxMax(bestSize.x,minWidth),
199                   wxMin(bestSize.y,maxHeight));
200 }
201
202 // ----------------------------------------------------------------------------
203 // wxComboBox
204 // ----------------------------------------------------------------------------
205
206 void wxComboBox::Init()
207 {
208     m_lbox = NULL;
209 }
210
211 wxComboBox::wxComboBox(wxWindow *parent,
212                        wxWindowID id,
213                        const wxString& value,
214                        const wxPoint& pos,
215                        const wxSize& size,
216                        const wxArrayString& choices,
217                        long style,
218                        const wxValidator& validator,
219                        const wxString& name)
220 {
221     Init();
222
223     Create(parent, id, value, pos, size, choices, style, validator, name);
224 }
225
226 bool wxComboBox::Create(wxWindow *parent,
227                         wxWindowID id,
228                         const wxString& value,
229                         const wxPoint& pos,
230                         const wxSize& size,
231                         const wxArrayString& choices,
232                         long style,
233                         const wxValidator& validator,
234                         const wxString& name)
235 {
236     wxCArrayString chs(choices);
237
238     return Create(parent, id, value, pos, size, chs.GetCount(),
239                   chs.GetStrings(), style, validator, name);
240 }
241
242 bool wxComboBox::Create(wxWindow *parent,
243                         wxWindowID id,
244                         const wxString& value,
245                         const wxPoint& pos,
246                         const wxSize& size,
247                         int n,
248                         const wxString choices[],
249                         long style,
250                         const wxValidator& validator,
251                         const wxString& name)
252 {
253     if ( !wxComboCtrl::Create(parent, id, value, pos, size, style,
254                                  validator, name) )
255     {
256         return false;
257     }
258
259     wxComboListBox *combolbox = new wxComboListBox();
260     SetPopupControl(combolbox);
261
262     m_lbox = combolbox;
263     m_lbox->Set(n, choices);
264
265     return true;
266 }
267
268 wxComboBox::~wxComboBox()
269 {
270 }
271
272 // ----------------------------------------------------------------------------
273 // wxComboBox methods forwarded to wxTextCtrl
274 // ----------------------------------------------------------------------------
275
276 wxString wxComboBox::DoGetValue() const
277 {
278     return wxComboCtrl::GetValue();
279 }
280
281 void wxComboBox::SetValue(const wxString& value)
282 {
283     wxComboCtrl::SetValue(value);
284 }
285
286 void wxComboBox::WriteText(const wxString& value)
287 {
288     if ( GetTextCtrl() ) GetTextCtrl()->WriteText(value);
289 }
290
291 void wxComboBox::Copy()
292 {
293     if ( GetTextCtrl() ) GetTextCtrl()->Copy();
294 }
295
296 void wxComboBox::Cut()
297 {
298     if ( GetTextCtrl() ) GetTextCtrl()->Cut();
299 }
300
301 void wxComboBox::Paste()
302 {
303     if ( GetTextCtrl() ) GetTextCtrl()->Paste();
304 }
305
306 void wxComboBox::SetInsertionPoint(long pos)
307 {
308     if ( GetTextCtrl() ) GetTextCtrl()->SetInsertionPoint(pos);
309 }
310
311 void wxComboBox::SetInsertionPointEnd()
312 {
313     if ( GetTextCtrl() ) GetTextCtrl()->SetInsertionPointEnd();
314 }
315
316 long wxComboBox::GetInsertionPoint() const
317 {
318     if ( GetTextCtrl() )
319         return GetTextCtrl()->GetInsertionPoint();
320     return -1;
321 }
322
323 wxTextPos wxComboBox::GetLastPosition() const
324 {
325     if ( GetTextCtrl() )
326         return GetTextCtrl()->GetLastPosition();
327     return -1;
328 }
329
330 void wxComboBox::Replace(long from, long to, const wxString& value)
331 {
332     if ( GetTextCtrl() ) GetTextCtrl()->Replace(from, to, value);
333 }
334
335 void wxComboBox::Remove(long from, long to)
336 {
337     if ( GetTextCtrl() ) GetTextCtrl()->Remove(from, to);
338 }
339
340 void wxComboBox::SetSelection(long from, long to)
341 {
342     if ( GetTextCtrl() ) GetTextCtrl()->SetSelection(from, to);
343 }
344
345 void wxComboBox::GetSelection(long *from, long *to) const
346 {
347     if ( GetTextCtrl() ) GetTextCtrl()->GetSelection(from, to);
348 }
349
350 void wxComboBox::SetEditable(bool editable)
351 {
352     if ( GetTextCtrl() ) GetTextCtrl()->SetEditable(editable);
353 }
354
355 // ----------------------------------------------------------------------------
356 // wxComboBox methods forwarded to wxListBox
357 // ----------------------------------------------------------------------------
358
359 void wxComboBox::DoClear()
360 {
361     GetLBox()->Clear();
362     if ( GetTextCtrl() ) GetTextCtrl()->SetValue(wxEmptyString);
363 }
364
365 void wxComboBox::DoDeleteOneItem(unsigned int n)
366 {
367     wxCHECK_RET( IsValid(n), _T("invalid index in wxComboBox::Delete") );
368
369     if (GetSelection() == (int)n)
370         if ( GetTextCtrl() ) GetTextCtrl()->SetValue(wxEmptyString);
371
372     GetLBox()->Delete(n);
373 }
374
375 unsigned int wxComboBox::GetCount() const
376 {
377     return GetLBox()->GetCount();
378 }
379
380 wxString wxComboBox::GetString(unsigned int n) const
381 {
382     wxCHECK_MSG( IsValid(n), wxEmptyString, _T("invalid index in wxComboBox::GetString") );
383
384     return GetLBox()->GetString(n);
385 }
386
387 void wxComboBox::SetString(unsigned int n, const wxString& s)
388 {
389     wxCHECK_RET( IsValid(n), _T("invalid index in wxComboBox::SetString") );
390
391     GetLBox()->SetString(n, s);
392 }
393
394 int wxComboBox::FindString(const wxString& s, bool bCase) const
395 {
396     return GetLBox()->FindString(s, bCase);
397 }
398
399 void wxComboBox::SetSelection(int n)
400 {
401     wxCHECK_RET( (n == wxNOT_FOUND || IsValid(n)), _T("invalid index in wxComboBox::Select") );
402
403     GetLBox()->SetSelection(n);
404
405     wxString str;
406     if ( n != wxNOT_FOUND )
407         str = GetLBox()->GetString(n);
408
409     SetText(str);
410 }
411
412 int wxComboBox::GetSelection() const
413 {
414 #if 1 // FIXME:: What is the correct behavior?
415     // if the current value isn't one of the listbox strings, return -1
416     return GetLBox()->GetSelection();
417 #else
418     // Why oh why is this done this way?
419     // It is not because the value displayed in the text can be found
420     // in the list that it is the item that is selected!
421     return FindString(if ( GetTextCtrl() ) GetTextCtrl()->GetValue());
422 #endif
423 }
424
425 wxString wxComboBox::GetStringSelection() const
426 {
427     return GetLBox()->GetStringSelection();
428 }
429
430 wxClientDataType wxComboBox::GetClientDataType() const
431 {
432     return GetLBox()->GetClientDataType();
433 }
434
435 void wxComboBox::SetClientDataType(wxClientDataType clientDataItemsType)
436 {
437     GetLBox()->SetClientDataType(clientDataItemsType);
438 }
439
440 int wxComboBox::DoInsertItems(const wxArrayStringsAdapter & items,
441                               unsigned int pos,
442                               void **clientData, wxClientDataType type)
443 {
444     return GetLBox()->DoInsertItems(items, pos, clientData, type);
445 }
446
447 void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
448 {
449     GetLBox()->DoSetItemClientData(n, clientData);
450 }
451
452 void *wxComboBox::DoGetItemClientData(unsigned int n) const
453 {
454     return GetLBox()->DoGetItemClientData(n);
455 }
456
457 bool wxComboBox::IsEditable() const
458 {
459     return GetTextCtrl() != NULL && (!HasFlag(wxCB_READONLY) || GetTextCtrl()->IsEditable() );
460 }
461
462 void wxComboBox::Undo()
463 {
464     if (IsEditable())
465         if ( GetTextCtrl() ) GetTextCtrl()->Undo();
466 }
467
468 void wxComboBox::Redo()
469 {
470     if (IsEditable())
471         if ( GetTextCtrl() ) GetTextCtrl()->Redo();
472 }
473
474 void wxComboBox::SelectAll()
475 {
476     if ( GetTextCtrl() ) GetTextCtrl()->SelectAll();
477 }
478
479 bool wxComboBox::CanCopy() const
480 {
481     if (GetTextCtrl() != NULL)
482         return GetTextCtrl()->CanCopy();
483     else
484         return false;
485 }
486
487 bool wxComboBox::CanCut() const
488 {
489     if (GetTextCtrl() != NULL)
490         return GetTextCtrl()->CanCut();
491     else
492         return false;
493 }
494
495 bool wxComboBox::CanPaste() const
496 {
497     if (IsEditable())
498         return GetTextCtrl()->CanPaste();
499     else
500         return false;
501 }
502
503 bool wxComboBox::CanUndo() const
504 {
505     if (IsEditable())
506         return GetTextCtrl()->CanUndo();
507     else
508         return false;
509 }
510
511 bool wxComboBox::CanRedo() const
512 {
513     if (IsEditable())
514         return GetTextCtrl()->CanRedo();
515     else
516         return false;
517 }
518
519
520 // ----------------------------------------------------------------------------
521 // wxStdComboBoxInputHandler
522 // ----------------------------------------------------------------------------
523
524 wxStdComboBoxInputHandler::wxStdComboBoxInputHandler(wxInputHandler *inphand)
525                          : wxStdInputHandler(inphand)
526 {
527 }
528
529 bool wxStdComboBoxInputHandler::HandleKey(wxInputConsumer *consumer,
530                                           const wxKeyEvent& event,
531                                           bool pressed)
532 {
533     if ( pressed )
534     {
535         wxControlAction action;
536         switch ( event.GetKeyCode() )
537         {
538             case WXK_DOWN:
539                 action = wxACTION_COMBOBOX_POPUP;
540                 break;
541
542             case WXK_ESCAPE:
543                 action = wxACTION_COMBOBOX_DISMISS;
544                 break;
545         }
546
547         if ( !action.IsEmpty() )
548         {
549             consumer->PerformAction(action);
550
551             return true;
552         }
553     }
554
555     return wxStdInputHandler::HandleKey(consumer, event, pressed);
556 }
557
558 /* static */
559 wxInputHandler *wxComboBox::GetStdInputHandler(wxInputHandler *handlerDef)
560 {
561     static wxStdComboBoxInputHandler s_handler(handlerDef);
562
563     return &s_handler;
564 }
565
566 #endif // wxUSE_COMBOBOX