fix access to client data of wxComboBox in wxUniv by virtualizing access to wxControl...
[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->ProcessEvent(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 = (wxListBox *)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::GetValue() 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::Copy()
287 {
288 if ( GetTextCtrl() ) GetTextCtrl()->Copy();
289 }
290
291 void wxComboBox::Cut()
292 {
293 if ( GetTextCtrl() ) GetTextCtrl()->Cut();
294 }
295
296 void wxComboBox::Paste()
297 {
298 if ( GetTextCtrl() ) GetTextCtrl()->Paste();
299 }
300
301 void wxComboBox::SetInsertionPoint(long pos)
302 {
303 if ( GetTextCtrl() ) GetTextCtrl()->SetInsertionPoint(pos);
304 }
305
306 void wxComboBox::SetInsertionPointEnd()
307 {
308 if ( GetTextCtrl() ) GetTextCtrl()->SetInsertionPointEnd();
309 }
310
311 long wxComboBox::GetInsertionPoint() const
312 {
313 if ( GetTextCtrl() )
314 return GetTextCtrl()->GetInsertionPoint();
315 return -1;
316 }
317
318 wxTextPos wxComboBox::GetLastPosition() const
319 {
320 if ( GetTextCtrl() )
321 return GetTextCtrl()->GetLastPosition();
322 return -1;
323 }
324
325 void wxComboBox::Replace(long from, long to, const wxString& value)
326 {
327 if ( GetTextCtrl() ) GetTextCtrl()->Replace(from, to, value);
328 }
329
330 void wxComboBox::Remove(long from, long to)
331 {
332 if ( GetTextCtrl() ) GetTextCtrl()->Remove(from, to);
333 }
334
335 void wxComboBox::SetSelection(long from, long to)
336 {
337 if ( GetTextCtrl() ) GetTextCtrl()->SetSelection(from, to);
338 }
339
340 void wxComboBox::SetEditable(bool editable)
341 {
342 if ( GetTextCtrl() ) GetTextCtrl()->SetEditable(editable);
343 }
344
345 // ----------------------------------------------------------------------------
346 // wxComboBox methods forwarded to wxListBox
347 // ----------------------------------------------------------------------------
348
349 void wxComboBox::DoClear()
350 {
351 GetLBox()->Clear();
352 if ( GetTextCtrl() ) GetTextCtrl()->SetValue(wxEmptyString);
353 }
354
355 void wxComboBox::DoDeleteOneItem(unsigned int n)
356 {
357 wxCHECK_RET( IsValid(n), _T("invalid index in wxComboBox::Delete") );
358
359 if (GetSelection() == (int)n)
360 if ( GetTextCtrl() ) GetTextCtrl()->SetValue(wxEmptyString);
361
362 GetLBox()->Delete(n);
363 }
364
365 unsigned int wxComboBox::GetCount() const
366 {
367 return GetLBox()->GetCount();
368 }
369
370 wxString wxComboBox::GetString(unsigned int n) const
371 {
372 wxCHECK_MSG( IsValid(n), wxEmptyString, _T("invalid index in wxComboBox::GetString") );
373
374 return GetLBox()->GetString(n);
375 }
376
377 void wxComboBox::SetString(unsigned int n, const wxString& s)
378 {
379 wxCHECK_RET( IsValid(n), _T("invalid index in wxComboBox::SetString") );
380
381 GetLBox()->SetString(n, s);
382 }
383
384 int wxComboBox::FindString(const wxString& s, bool bCase) const
385 {
386 return GetLBox()->FindString(s, bCase);
387 }
388
389 void wxComboBox::SetSelection(int n)
390 {
391 wxCHECK_RET( (n == wxNOT_FOUND || IsValid(n)), _T("invalid index in wxComboBox::Select") );
392
393 GetLBox()->SetSelection(n);
394
395 wxString str;
396 if ( n != wxNOT_FOUND )
397 str = GetLBox()->GetString(n);
398
399 SetText(str);
400 }
401
402 int wxComboBox::GetSelection() const
403 {
404 #if 1 // FIXME:: What is the correct behavior?
405 // if the current value isn't one of the listbox strings, return -1
406 return GetLBox()->GetSelection();
407 #else
408 // Why oh why is this done this way?
409 // It is not because the value displayed in the text can be found
410 // in the list that it is the item that is selected!
411 return FindString(if ( GetTextCtrl() ) GetTextCtrl()->GetValue());
412 #endif
413 }
414
415 void wxComboBox::SetClientDataType(wxClientDataType clientDataItemsType)
416 {
417 GetLBox()->SetClientDataType(clientDataItemsType);
418 }
419
420 int wxComboBox::DoInsertItems(const wxArrayStringsAdapter & items,
421 unsigned int pos,
422 void **clientData, wxClientDataType type)
423 {
424 return GetLBox()->DoInsertItems(items, pos, clientData, type);
425 }
426
427 void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
428 {
429 GetLBox()->DoSetItemClientData(n, clientData);
430 }
431
432 void *wxComboBox::DoGetItemClientData(unsigned int n) const
433 {
434 return GetLBox()->DoGetItemClientData(n);
435 }
436
437 bool wxComboBox::IsEditable() const
438 {
439 return GetTextCtrl() != NULL && (!HasFlag(wxCB_READONLY) || GetTextCtrl()->IsEditable() );
440 }
441
442 void wxComboBox::Undo()
443 {
444 if (IsEditable())
445 if ( GetTextCtrl() ) GetTextCtrl()->Undo();
446 }
447
448 void wxComboBox::Redo()
449 {
450 if (IsEditable())
451 if ( GetTextCtrl() ) GetTextCtrl()->Redo();
452 }
453
454 void wxComboBox::SelectAll()
455 {
456 if ( GetTextCtrl() ) GetTextCtrl()->SelectAll();
457 }
458
459 bool wxComboBox::CanCopy() const
460 {
461 if (GetTextCtrl() != NULL)
462 return GetTextCtrl()->CanCopy();
463 else
464 return false;
465 }
466
467 bool wxComboBox::CanCut() const
468 {
469 if (GetTextCtrl() != NULL)
470 return GetTextCtrl()->CanCut();
471 else
472 return false;
473 }
474
475 bool wxComboBox::CanPaste() const
476 {
477 if (IsEditable())
478 return GetTextCtrl()->CanPaste();
479 else
480 return false;
481 }
482
483 bool wxComboBox::CanUndo() const
484 {
485 if (IsEditable())
486 return GetTextCtrl()->CanUndo();
487 else
488 return false;
489 }
490
491 bool wxComboBox::CanRedo() const
492 {
493 if (IsEditable())
494 return GetTextCtrl()->CanRedo();
495 else
496 return false;
497 }
498
499
500 // ----------------------------------------------------------------------------
501 // wxStdComboBoxInputHandler
502 // ----------------------------------------------------------------------------
503
504 wxStdComboBoxInputHandler::wxStdComboBoxInputHandler(wxInputHandler *inphand)
505 : wxStdInputHandler(inphand)
506 {
507 }
508
509 bool wxStdComboBoxInputHandler::HandleKey(wxInputConsumer *consumer,
510 const wxKeyEvent& event,
511 bool pressed)
512 {
513 if ( pressed )
514 {
515 wxControlAction action;
516 switch ( event.GetKeyCode() )
517 {
518 case WXK_DOWN:
519 action = wxACTION_COMBOBOX_POPUP;
520 break;
521
522 case WXK_ESCAPE:
523 action = wxACTION_COMBOBOX_DISMISS;
524 break;
525 }
526
527 if ( !action.IsEmpty() )
528 {
529 consumer->PerformAction(action);
530
531 return true;
532 }
533 }
534
535 return wxStdInputHandler::HandleKey(consumer, event, pressed);
536 }
537
538 /* static */
539 wxInputHandler *wxComboBox::GetStdInputHandler(wxInputHandler *handlerDef)
540 {
541 static wxStdComboBoxInputHandler s_handler(handlerDef);
542
543 return &s_handler;
544 }
545
546 #endif // wxUSE_COMBOBOX