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