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