XRC: make wxStaticText's wrap property a dimension.
[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 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 #include "wx/wxprec.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 #if wxUSE_COMBOBOX
26
27 #ifndef WX_PRECOMP
28 #include "wx/log.h"
29
30 #include "wx/button.h"
31 #include "wx/combobox.h"
32 #include "wx/listbox.h"
33 #include "wx/textctrl.h"
34 #include "wx/bmpbuttn.h"
35
36 #include "wx/validate.h"
37 #endif
38
39 #include "wx/tooltip.h"
40 #include "wx/combo.h"
41
42 #include "wx/univ/renderer.h"
43 #include "wx/univ/inphand.h"
44 #include "wx/univ/theme.h"
45
46 // ----------------------------------------------------------------------------
47 // wxStdComboBoxInputHandler: allows the user to open/close the combo from kbd
48 // ----------------------------------------------------------------------------
49
50 class WXDLLEXPORT wxStdComboBoxInputHandler : public wxStdInputHandler
51 {
52 public:
53 wxStdComboBoxInputHandler(wxInputHandler *inphand);
54
55 virtual bool HandleKey(wxInputConsumer *consumer,
56 const wxKeyEvent& event,
57 bool pressed);
58 };
59
60 // ----------------------------------------------------------------------------
61 // wxComboListBox is a listbox modified to be used as a popup window in a
62 // combobox
63 // ----------------------------------------------------------------------------
64
65 class wxComboListBox : public wxListBox, public wxComboPopup
66 {
67 public:
68 // ctor and dtor
69 wxComboListBox();
70 virtual ~wxComboListBox();
71
72 // implement wxComboPopup methods
73 virtual bool Create(wxWindow* parent);
74 virtual void SetStringValue(const wxString& s);
75 virtual wxString GetStringValue() const;
76 virtual wxWindow *GetControl() { return this; }
77 virtual void OnPopup();
78 virtual wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight);
79
80 // fix virtual function hiding
81 virtual void SetSelection(int n) { DoSetSelection(n, true); }
82 void SetSelection(int n, bool select) { DoSetSelection(n, select); }
83
84 // used to process wxUniv actions
85 bool PerformAction(const wxControlAction& action,
86 long numArg,
87 const wxString& strArg);
88
89 protected:
90 // set m_clicked value from here
91 void OnLeftUp(wxMouseEvent& event);
92
93 private:
94 friend class wxComboBox; // it accesses our DoGetItemClientData()
95
96 DECLARE_EVENT_TABLE()
97 };
98
99 // ----------------------------------------------------------------------------
100 // event tables and such
101 // ----------------------------------------------------------------------------
102
103 BEGIN_EVENT_TABLE(wxComboListBox, wxListBox)
104 EVT_LEFT_UP(wxComboListBox::OnLeftUp)
105 END_EVENT_TABLE()
106
107 // ============================================================================
108 // implementation
109 // ============================================================================
110
111 // ----------------------------------------------------------------------------
112 // wxComboListBox
113 // ----------------------------------------------------------------------------
114
115 wxComboListBox::wxComboListBox() : wxListBox(), wxComboPopup()
116 {
117 }
118
119 bool wxComboListBox::Create(wxWindow* parent)
120 {
121 if ( !wxListBox::Create(parent, wxID_ANY,
122 wxDefaultPosition, wxDefaultSize,
123 0, NULL,
124 wxBORDER_SIMPLE |
125 ( m_combo->GetWindowStyle() & wxCB_SORT ? wxLB_SORT : 0 ) ) )
126 return false;
127
128 // we don't react to the mouse events outside the window at all
129 StopAutoScrolling();
130
131 return true;
132 }
133
134 wxComboListBox::~wxComboListBox()
135 {
136 }
137
138 wxString wxComboListBox::GetStringValue() const
139 {
140 return wxListBox::GetStringSelection();
141 }
142
143 void wxComboListBox::SetStringValue(const wxString& value)
144 {
145 if ( !value.empty() )
146 {
147 if (FindString(value) != wxNOT_FOUND)
148 wxListBox::SetStringSelection(value);
149 }
150 else
151 wxListBox::SetSelection(-1);
152 }
153
154 void wxComboListBox::OnPopup()
155 {
156 }
157
158 bool wxComboListBox::PerformAction(const wxControlAction& action,
159 long numArg,
160 const wxString& strArg)
161
162 {
163 if ( action == wxACTION_LISTBOX_FIND )
164 {
165 // we don't let the listbox handle this as instead of just using the
166 // single key presses, as usual, we use the text ctrl value as prefix
167 // and this is done by wxComboCtrl itself
168 return true;
169 }
170
171 return wxListBox::PerformAction(action, numArg, strArg);
172 }
173
174 void wxComboListBox::OnLeftUp(wxMouseEvent& event)
175 {
176 // we should dismiss the combo now
177 // first update the combo and close the listbox
178 Dismiss();
179 m_combo->SetValue(wxListBox::GetStringSelection());
180
181 // next let the user code have the event
182 wxCommandEvent evt(wxEVT_COMBOBOX,m_combo->GetId());
183 evt.SetInt(wxListBox::GetSelection());
184 evt.SetEventObject(m_combo);
185 m_combo->ProcessWindowEvent(evt);
186
187 event.Skip();
188 }
189
190 wxSize wxComboListBox::GetAdjustedSize(int minWidth,
191 int WXUNUSED(prefHeight),
192 int maxHeight)
193 {
194 wxSize bestSize = wxListBox::GetBestSize();
195 return wxSize(wxMax(bestSize.x,minWidth),
196 wxMin(bestSize.y,maxHeight));
197 }
198
199 // ----------------------------------------------------------------------------
200 // wxComboBox
201 // ----------------------------------------------------------------------------
202
203 void wxComboBox::Init()
204 {
205 m_lbox = NULL;
206 }
207
208 wxComboBox::wxComboBox(wxWindow *parent,
209 wxWindowID id,
210 const wxString& value,
211 const wxPoint& pos,
212 const wxSize& size,
213 const wxArrayString& choices,
214 long style,
215 const wxValidator& validator,
216 const wxString& name)
217 {
218 Init();
219
220 Create(parent, id, value, pos, size, choices, style, validator, name);
221 }
222
223 bool wxComboBox::Create(wxWindow *parent,
224 wxWindowID id,
225 const wxString& value,
226 const wxPoint& pos,
227 const wxSize& size,
228 const wxArrayString& choices,
229 long style,
230 const wxValidator& validator,
231 const wxString& name)
232 {
233 wxCArrayString chs(choices);
234
235 return Create(parent, id, value, pos, size, chs.GetCount(),
236 chs.GetStrings(), style, validator, name);
237 }
238
239 bool wxComboBox::Create(wxWindow *parent,
240 wxWindowID id,
241 const wxString& value,
242 const wxPoint& pos,
243 const wxSize& size,
244 int n,
245 const wxString choices[],
246 long style,
247 const wxValidator& validator,
248 const wxString& name)
249 {
250 if ( !wxComboCtrl::Create(parent, id, value, pos, size, style,
251 validator, name) )
252 {
253 return false;
254 }
255
256 wxComboListBox *combolbox = new wxComboListBox();
257 SetPopupControl(combolbox);
258
259 m_lbox = combolbox;
260 m_lbox->Set(n, choices);
261
262 return true;
263 }
264
265 wxComboBox::~wxComboBox()
266 {
267 }
268
269 // ----------------------------------------------------------------------------
270 // wxComboBox methods forwarded to wxTextCtrl
271 // ----------------------------------------------------------------------------
272
273 wxString wxComboBox::DoGetValue() const
274 {
275 return GetTextCtrl() ? GetTextCtrl()->GetValue() : m_valueString;
276 }
277
278 void wxComboBox::SetValue(const wxString& value)
279 {
280 if ( GetTextCtrl() )
281 GetTextCtrl()->SetValue(value);
282 else
283 m_valueString = 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 SetValue(wxEmptyString);
363 }
364
365 void wxComboBox::DoDeleteOneItem(unsigned int n)
366 {
367 wxCHECK_RET( IsValid(n), wxT("invalid index in wxComboBox::Delete") );
368
369 if (GetSelection() == (int)n)
370 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, wxT("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), wxT("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)), wxT("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 behaviour?
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