]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/univ/combobox.cpp
fix Get(Sub)ItemRect() after changes of r54437; added test for it (see #10175)
[wxWidgets.git] / src / univ / combobox.cpp
... / ...
CommitLineData
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
51class WXDLLEXPORT wxStdComboBoxInputHandler : public wxStdInputHandler
52{
53public:
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
66class wxComboListBox : public wxListBox, public wxComboPopup
67{
68public:
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
90protected:
91 // set m_clicked value from here
92 void OnLeftUp(wxMouseEvent& event);
93
94private:
95 friend class wxComboBox; // it accesses our DoGetItemClientData()
96
97 DECLARE_EVENT_TABLE()
98};
99
100// ----------------------------------------------------------------------------
101// event tables and such
102// ----------------------------------------------------------------------------
103
104BEGIN_EVENT_TABLE(wxComboListBox, wxListBox)
105 EVT_LEFT_UP(wxComboListBox::OnLeftUp)
106END_EVENT_TABLE()
107
108IMPLEMENT_DYNAMIC_CLASS2(wxComboBox, wxControl, wxComboCtrl)
109
110// ============================================================================
111// implementation
112// ============================================================================
113
114// ----------------------------------------------------------------------------
115// wxComboListBox
116// ----------------------------------------------------------------------------
117
118wxComboListBox::wxComboListBox() : wxListBox(), wxComboPopup()
119{
120}
121
122bool 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
137wxComboListBox::~wxComboListBox()
138{
139}
140
141wxString wxComboListBox::GetStringValue() const
142{
143 return wxListBox::GetStringSelection();
144}
145
146void 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
157void wxComboListBox::OnPopup()
158{
159}
160
161bool 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
177void 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
193wxSize 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
206void wxComboBox::Init()
207{
208 m_lbox = (wxListBox *)NULL;
209}
210
211wxComboBox::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
226bool 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
242bool 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
268wxComboBox::~wxComboBox()
269{
270}
271
272// ----------------------------------------------------------------------------
273// wxComboBox methods forwarded to wxTextCtrl
274// ----------------------------------------------------------------------------
275
276wxString wxComboBox::GetValue() const
277{
278 return wxComboCtrl::GetValue();
279}
280
281void wxComboBox::SetValue(const wxString& value)
282{
283 wxComboCtrl::SetValue(value);
284}
285
286void wxComboBox::WriteText(const wxString& value)
287{
288 if ( GetTextCtrl() ) GetTextCtrl()->WriteText(value);
289}
290
291void wxComboBox::Copy()
292{
293 if ( GetTextCtrl() ) GetTextCtrl()->Copy();
294}
295
296void wxComboBox::Cut()
297{
298 if ( GetTextCtrl() ) GetTextCtrl()->Cut();
299}
300
301void wxComboBox::Paste()
302{
303 if ( GetTextCtrl() ) GetTextCtrl()->Paste();
304}
305
306void wxComboBox::SetInsertionPoint(long pos)
307{
308 if ( GetTextCtrl() ) GetTextCtrl()->SetInsertionPoint(pos);
309}
310
311void wxComboBox::SetInsertionPointEnd()
312{
313 if ( GetTextCtrl() ) GetTextCtrl()->SetInsertionPointEnd();
314}
315
316long wxComboBox::GetInsertionPoint() const
317{
318 if ( GetTextCtrl() )
319 return GetTextCtrl()->GetInsertionPoint();
320 return -1;
321}
322
323wxTextPos wxComboBox::GetLastPosition() const
324{
325 if ( GetTextCtrl() )
326 return GetTextCtrl()->GetLastPosition();
327 return -1;
328}
329
330void wxComboBox::Replace(long from, long to, const wxString& value)
331{
332 if ( GetTextCtrl() ) GetTextCtrl()->Replace(from, to, value);
333}
334
335void wxComboBox::Remove(long from, long to)
336{
337 if ( GetTextCtrl() ) GetTextCtrl()->Remove(from, to);
338}
339
340void wxComboBox::SetSelection(long from, long to)
341{
342 if ( GetTextCtrl() ) GetTextCtrl()->SetSelection(from, to);
343}
344
345void wxComboBox::GetSelection(long *from, long *to) const
346{
347 if ( GetTextCtrl() ) GetTextCtrl()->GetSelection(from, to);
348}
349
350void wxComboBox::SetEditable(bool editable)
351{
352 if ( GetTextCtrl() ) GetTextCtrl()->SetEditable(editable);
353}
354
355// ----------------------------------------------------------------------------
356// wxComboBox methods forwarded to wxListBox
357// ----------------------------------------------------------------------------
358
359void wxComboBox::DoClear()
360{
361 GetLBox()->Clear();
362 if ( GetTextCtrl() ) GetTextCtrl()->SetValue(wxEmptyString);
363}
364
365void wxComboBox::DoDeleteOneItem(unsigned int n)
366{
367 wxCHECK_RET( IsValid(n), _T("invalid index in wxComboBox::Delete") );
368
369 if (GetSelection() == (int)n)
370 if ( GetTextCtrl() ) GetTextCtrl()->SetValue(wxEmptyString);
371
372 GetLBox()->Delete(n);
373}
374
375unsigned int wxComboBox::GetCount() const
376{
377 return GetLBox()->GetCount();
378}
379
380wxString wxComboBox::GetString(unsigned int n) const
381{
382 wxCHECK_MSG( IsValid(n), wxEmptyString, _T("invalid index in wxComboBox::GetString") );
383
384 return GetLBox()->GetString(n);
385}
386
387void wxComboBox::SetString(unsigned int n, const wxString& s)
388{
389 wxCHECK_RET( IsValid(n), _T("invalid index in wxComboBox::SetString") );
390
391 GetLBox()->SetString(n, s);
392}
393
394int wxComboBox::FindString(const wxString& s, bool bCase) const
395{
396 return GetLBox()->FindString(s, bCase);
397}
398
399void wxComboBox::SetSelection(int n)
400{
401 wxCHECK_RET( (n == wxNOT_FOUND || IsValid(n)), _T("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
412int wxComboBox::GetSelection() const
413{
414#if 1 // FIXME:: What is the correct behavior?
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
425wxString wxComboBox::GetStringSelection() const
426{
427 return GetLBox()->GetStringSelection();
428}
429
430wxClientDataType wxComboBox::GetClientDataType() const
431{
432 return GetLBox()->GetClientDataType();
433}
434
435void wxComboBox::SetClientDataType(wxClientDataType clientDataItemsType)
436{
437 GetLBox()->SetClientDataType(clientDataItemsType);
438}
439
440int 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
447void wxComboBox::DoSetItemClientData(unsigned int n, void* clientData)
448{
449 GetLBox()->DoSetItemClientData(n, clientData);
450}
451
452void *wxComboBox::DoGetItemClientData(unsigned int n) const
453{
454 return GetLBox()->DoGetItemClientData(n);
455}
456
457bool wxComboBox::IsEditable() const
458{
459 return GetTextCtrl() != NULL && (!HasFlag(wxCB_READONLY) || GetTextCtrl()->IsEditable() );
460}
461
462void wxComboBox::Undo()
463{
464 if (IsEditable())
465 if ( GetTextCtrl() ) GetTextCtrl()->Undo();
466}
467
468void wxComboBox::Redo()
469{
470 if (IsEditable())
471 if ( GetTextCtrl() ) GetTextCtrl()->Redo();
472}
473
474void wxComboBox::SelectAll()
475{
476 if ( GetTextCtrl() ) GetTextCtrl()->SelectAll();
477}
478
479bool wxComboBox::CanCopy() const
480{
481 if (GetTextCtrl() != NULL)
482 return GetTextCtrl()->CanCopy();
483 else
484 return false;
485}
486
487bool wxComboBox::CanCut() const
488{
489 if (GetTextCtrl() != NULL)
490 return GetTextCtrl()->CanCut();
491 else
492 return false;
493}
494
495bool wxComboBox::CanPaste() const
496{
497 if (IsEditable())
498 return GetTextCtrl()->CanPaste();
499 else
500 return false;
501}
502
503bool wxComboBox::CanUndo() const
504{
505 if (IsEditable())
506 return GetTextCtrl()->CanUndo();
507 else
508 return false;
509}
510
511bool wxComboBox::CanRedo() const
512{
513 if (IsEditable())
514 return GetTextCtrl()->CanRedo();
515 else
516 return false;
517}
518
519
520// ----------------------------------------------------------------------------
521// wxStdComboBoxInputHandler
522// ----------------------------------------------------------------------------
523
524wxStdComboBoxInputHandler::wxStdComboBoxInputHandler(wxInputHandler *inphand)
525 : wxStdInputHandler(inphand)
526{
527}
528
529bool 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 */
559wxInputHandler *wxComboBox::GetStdInputHandler(wxInputHandler *handlerDef)
560{
561 static wxStdComboBoxInputHandler s_handler(handlerDef);
562
563 return &s_handler;
564}
565
566#endif // wxUSE_COMBOBOX