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