]> git.saurik.com Git - wxWidgets.git/blame - src/motif/choice.cpp
use unsgined int instead of int for 1 bit bitfields (SGI CC warning fix)
[wxWidgets.git] / src / motif / choice.cpp
CommitLineData
4bb6408c
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: choice.cpp
3// Purpose: wxChoice
4// Author: Julian Smart
5// Modified by:
6// Created: 17/09/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
312ebad4 9// Licence: wxWindows licence
4bb6408c
JS
10/////////////////////////////////////////////////////////////////////////////
11
14f355c2 12#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
4bb6408c
JS
13#pragma implementation "choice.h"
14#endif
15
1248b41f
MB
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
bcd055ae 19#ifdef __VMS
4dff3400
JJ
20#define XtDisplay XTDISPLAY
21#define XtParent XTPARENT
22#endif
23
f6045f99
GD
24#include "wx/defs.h"
25
312ebad4
WS
26#if wxUSE_CHOICE
27
4bb6408c 28#include "wx/choice.h"
f97c9854 29#include "wx/utils.h"
584ad2a3 30#include "wx/arrstr.h"
f97c9854 31
338dd992
JJ
32#ifdef __VMS__
33#pragma message disable nosimpint
34#endif
f97c9854
JS
35#include <Xm/Xm.h>
36#include <Xm/PushBG.h>
37#include <Xm/PushB.h>
38#include <Xm/RowColumn.h>
338dd992
JJ
39#ifdef __VMS__
40#pragma message enable nosimpint
41#endif
f97c9854
JS
42
43#include "wx/motif/private.h"
4bb6408c 44
3a73cc52
MB
45#define WIDTH_OVERHEAD 48
46#define WIDTH_OVERHEAD_SUBTRACT 40
47#define HEIGHT_OVERHEAD 15
48
4bb6408c 49IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
4bb6408c 50
f97c9854 51void wxChoiceCallback (Widget w, XtPointer clientData,
2d120f83 52 XtPointer ptr);
f97c9854
JS
53
54wxChoice::wxChoice()
55{
ec75d791
MB
56 Init();
57}
58
59void wxChoice::Init()
60{
f97c9854
JS
61 m_noStrings = 0;
62 m_buttonWidget = (WXWidget) 0;
63 m_menuWidget = (WXWidget) 0;
f97c9854 64 m_formWidget = (WXWidget) 0;
f97c9854
JS
65}
66
4bb6408c 67bool wxChoice::Create(wxWindow *parent, wxWindowID id,
2d120f83
JS
68 const wxPoint& pos,
69 const wxSize& size,
70 int n, const wxString choices[],
71 long style,
72 const wxValidator& validator,
73 const wxString& name)
4bb6408c 74{
ec75d791 75 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
312ebad4 76 return false;
31528cd3 77
f97c9854 78 Widget parentWidget = (Widget) parent->GetClientWidget();
31528cd3
VZ
79
80 m_formWidget = (WXWidget) XtVaCreateManagedWidget(name.c_str(),
2d120f83
JS
81 xmRowColumnWidgetClass, parentWidget,
82 XmNmarginHeight, 0,
83 XmNmarginWidth, 0,
84 XmNpacking, XmPACK_TIGHT,
85 XmNorientation, XmHORIZONTAL,
3a73cc52
MB
86 XmNresizeWidth, False,
87 XmNresizeHeight, False,
2d120f83 88 NULL);
31528cd3 89
f97c9854 90 XtVaSetValues ((Widget) m_formWidget, XmNspacing, 0, NULL);
31528cd3 91
2d120f83 92 /*
f97c9854
JS
93 * Create the popup menu
94 */
ec75d791 95 m_menuWidget = (WXWidget) XmCreatePulldownMenu ((Widget) m_formWidget,
f1db433a
VZ
96 wxMOTIF_STR("choiceMenu"),
97 NULL, 0);
31528cd3 98
f97c9854
JS
99 if (n > 0)
100 {
101 int i;
102 for (i = 0; i < n; i++)
103 Append (choices[i]);
104 }
31528cd3 105
2d120f83 106 /*
f97c9854
JS
107 * Create button
108 */
109 Arg args[10];
110 Cardinal argcnt = 0;
31528cd3 111
ec75d791
MB
112 XtSetArg (args[argcnt], XmNsubMenuId, (Widget) m_menuWidget); ++argcnt;
113 XtSetArg (args[argcnt], XmNmarginWidth, 0); ++argcnt;
114 XtSetArg (args[argcnt], XmNmarginHeight, 0); ++argcnt;
115 XtSetArg (args[argcnt], XmNpacking, XmPACK_TIGHT); ++argcnt;
116 m_buttonWidget = (WXWidget) XmCreateOptionMenu ((Widget) m_formWidget,
f1db433a 117 wxMOTIF_STR("choiceButton"),
ec75d791 118 args, argcnt);
31528cd3 119
f97c9854 120 m_mainWidget = m_buttonWidget;
31528cd3 121
f97c9854 122 XtManageChild ((Widget) m_buttonWidget);
9838df2c 123
f97c9854
JS
124 // New code from Roland Haenel (roland_haenel@ac.cybercity.de)
125 // Some time ago, I reported a problem with wxChoice-items under
126 // Linux and Motif 2.0 (they caused sporadic GPFs). Now it seems
127 // that I have found the code responsible for this behaviour.
128#if XmVersion >= 1002
129#if XmVersion < 2000
9838df2c
JS
130 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
131 // in controls sample.
dfe1eee3
VZ
132 //
133 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
134 // XtUnmanageChild (optionLabel);
f97c9854
JS
135#endif
136#endif
9838df2c 137
a29ee706
MB
138 wxSize bestSize = GetBestSize();
139 if( size.x > 0 ) bestSize.x = size.x;
140 if( size.y > 0 ) bestSize.y = size.y;
141
f97c9854 142 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
31528cd3 143
312ebad4 144 ChangeFont(false);
3a73cc52 145 ChangeBackgroundColour();
9838df2c 146
ec75d791 147 AttachWidget (parent, m_buttonWidget, m_formWidget,
a29ee706 148 pos.x, pos.y, bestSize.x, bestSize.y);
31528cd3 149
312ebad4 150 return true;
f97c9854
JS
151}
152
584ad2a3
MB
153bool wxChoice::Create(wxWindow *parent, wxWindowID id,
154 const wxPoint& pos,
155 const wxSize& size,
156 const wxArrayString& choices,
157 long style,
158 const wxValidator& validator,
159 const wxString& name)
160{
161 wxCArrayString chs(choices);
162 return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
163 style, validator, name);
164}
165
f97c9854
JS
166wxChoice::~wxChoice()
167{
2d120f83
JS
168 // For some reason destroying the menuWidget
169 // can cause crashes on some machines. It will
170 // be deleted implicitly by deleting the parent form
171 // anyway.
172 // XtDestroyWidget (menuWidget);
31528cd3 173
8aa04e8b
JS
174 if (GetMainWidget())
175 {
176 DetachWidget(GetMainWidget()); // Removes event handlers
b412f9be 177 DetachWidget(m_formWidget);
31528cd3 178
8aa04e8b
JS
179 XtDestroyWidget((Widget) m_formWidget);
180 m_formWidget = (WXWidget) 0;
31528cd3 181
8aa04e8b
JS
182 // Presumably the other widgets have been deleted now, via the form
183 m_mainWidget = (WXWidget) 0;
184 m_buttonWidget = (WXWidget) 0;
185 }
ec75d791
MB
186 if ( HasClientObjectData() )
187 m_clientDataDict.DestroyData();
4bb6408c
JS
188}
189
c33c81c3 190int wxChoice::DoAppend(const wxString& item)
4bb6408c 191{
31528cd3 192 Widget w = XtVaCreateManagedWidget (wxStripMenuCodes(item),
8c624a14 193#if wxUSE_GADGETS
2d120f83 194 xmPushButtonGadgetClass, (Widget) m_menuWidget,
f97c9854 195#else
2d120f83 196 xmPushButtonWidgetClass, (Widget) m_menuWidget,
f97c9854 197#endif
2d120f83 198 NULL);
31528cd3 199
a8680e3e 200 wxDoChangeBackgroundColour((WXWidget) w, m_backgroundColour);
31528cd3 201
e1aae528
MB
202 if( m_font.Ok() )
203 wxDoChangeFont( w, m_font );
31528cd3 204
ec75d791 205 m_widgetArray.Add(w);
31528cd3 206
3a73cc52 207 char mnem = wxFindMnemonic (item);
f6bcfd97
BP
208 if (mnem != 0)
209 XtVaSetValues (w, XmNmnemonic, mnem, NULL);
31528cd3 210
ec75d791
MB
211 XtAddCallback (w, XmNactivateCallback,
212 (XtCallbackProc) wxChoiceCallback,
213 (XtPointer) this);
31528cd3 214
f6bcfd97
BP
215 if (m_noStrings == 0 && m_buttonWidget)
216 {
217 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, w, NULL);
218 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
c13c9657 219 wxXmString text( item );
f6bcfd97 220 XtVaSetValues (label,
c13c9657 221 XmNlabelString, text(),
f6bcfd97 222 NULL);
f6bcfd97 223 }
ec75d791 224 m_stringList.Add(item);
f6bcfd97 225 m_noStrings ++;
c33c81c3 226
ec75d791 227 return GetCount() - 1;
4bb6408c
JS
228}
229
243dbf1a
VZ
230int wxChoice::DoInsert(const wxString& item, int pos)
231{
312ebad4 232 wxCHECK_MSG(false, -1, wxT("insert not implemented"));
243dbf1a
VZ
233
234// wxCHECK_MSG((pos>=0) && (pos<=GetCount()), -1, wxT("invalid index"));
235// if (pos == GetCount()) return DoAppend(item);
236}
237
ec75d791 238void wxChoice::Delete(int n)
4bb6408c 239{
ec75d791
MB
240 Widget w = (Widget)m_widgetArray[n];
241 XtRemoveCallback(w, XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
242 (XtPointer)this);
ac32ba44 243 m_stringList.Erase(m_stringList.Item(n));
ec75d791
MB
244 m_widgetArray.RemoveAt(size_t(n));
245 m_clientDataDict.Delete(n, HasClientObjectData());
31528cd3 246
ec75d791 247 XtDestroyWidget(w);
4bb6408c
JS
248 m_noStrings --;
249}
250
251void wxChoice::Clear()
252{
f97c9854 253 m_stringList.Clear ();
fd304d98 254 size_t i;
f97c9854
JS
255 for (i = 0; i < m_noStrings; i++)
256 {
ec75d791
MB
257 XtRemoveCallback((Widget) m_widgetArray[i],
258 XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
259 (XtPointer)this);
260 XtUnmanageChild ((Widget) m_widgetArray[i]);
261 XtDestroyWidget ((Widget) m_widgetArray[i]);
f97c9854 262 }
ec75d791 263 m_widgetArray.Clear();
f97c9854 264 if (m_buttonWidget)
ec75d791
MB
265 XtVaSetValues ((Widget) m_buttonWidget,
266 XmNmenuHistory, (Widget) NULL,
267 NULL);
f6bcfd97
BP
268
269 if ( HasClientObjectData() )
ec75d791 270 m_clientDataDict.DestroyData();
f6bcfd97 271
4bb6408c
JS
272 m_noStrings = 0;
273}
274
275int wxChoice::GetSelection() const
276{
2d120f83 277 XmString text;
2d120f83
JS
278 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
279 XtVaGetValues (label,
280 XmNlabelString, &text,
281 NULL);
da494b40
MB
282 wxXmString freeMe(text);
283 wxString s = wxXmStringToString( text );
31528cd3 284
da494b40 285 if (!s.IsEmpty())
2d120f83
JS
286 {
287 int i = 0;
ac32ba44 288 for (wxStringList::compatibility_iterator node = m_stringList.GetFirst ();
ec75d791 289 node; node = node->GetNext ())
f97c9854 290 {
da494b40 291 if (wxStrcmp(node->GetData(), s.c_str()) == 0)
2d120f83 292 {
2d120f83
JS
293 return i;
294 }
295 else
296 i++;
297 } // for()
31528cd3 298
2d120f83
JS
299 return -1;
300 }
2d120f83 301 return -1;
4bb6408c
JS
302}
303
304void wxChoice::SetSelection(int n)
305{
312ebad4 306 m_inSetValue = true;
31528cd3 307
ac32ba44 308 wxStringList::compatibility_iterator node = m_stringList.Item(n);
2d120f83 309 if (node)
f97c9854 310 {
ec75d791 311#if 0
2d120f83 312 Dimension selectionWidth, selectionHeight;
ec75d791 313#endif
fd304d98 314 wxXmString text( node->GetData() );
ec75d791
MB
315// MBN: this seems silly, at best, and causes wxChoices to be clipped:
316// will remove "soon"
317#if 0
318 XtVaGetValues ((Widget) m_widgetArray[n],
319 XmNwidth, &selectionWidth,
320 XmNheight, &selectionHeight,
321 NULL);
322#endif
2d120f83
JS
323 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
324 XtVaSetValues (label,
ec75d791 325 XmNlabelString, text(),
2d120f83 326 NULL);
ec75d791 327#if 0
2d120f83
JS
328 XtVaSetValues ((Widget) m_buttonWidget,
329 XmNwidth, selectionWidth, XmNheight, selectionHeight,
ec75d791
MB
330 XmNmenuHistory, (Widget) m_widgetArray[n], NULL);
331#endif
f97c9854 332 }
312ebad4 333 m_inSetValue = false;
4bb6408c
JS
334}
335
336int wxChoice::FindString(const wxString& s) const
337{
f97c9854 338 int i = 0;
ac32ba44 339 for (wxStringList::compatibility_iterator node = m_stringList.GetFirst();
ec75d791 340 node; node = node->GetNext ())
f97c9854 341 {
ec75d791 342 if (s == node->GetData())
f97c9854 343 return i;
ec75d791
MB
344
345 i++;
f97c9854 346 }
ec75d791 347
312ebad4 348 return wxNOT_FOUND;
4bb6408c
JS
349}
350
351wxString wxChoice::GetString(int n) const
352{
ac32ba44 353 wxStringList::compatibility_iterator node = m_stringList.Item(n);
2d120f83 354 if (node)
ec75d791 355 return node->GetData();
2d120f83
JS
356 else
357 return wxEmptyString;
f97c9854
JS
358}
359
360void wxChoice::SetColumns(int n)
361{
2d120f83 362 if (n<1) n = 1 ;
31528cd3 363
2d120f83
JS
364 short numColumns = n ;
365 Arg args[3];
31528cd3 366
2d120f83
JS
367 XtSetArg(args[0], XmNnumColumns, numColumns);
368 XtSetArg(args[1], XmNpacking, XmPACK_COLUMN);
369 XtSetValues((Widget) m_menuWidget,args,2) ;
f97c9854
JS
370}
371
372int wxChoice::GetColumns(void) const
373{
2d120f83 374 short numColumns ;
31528cd3 375
2d120f83
JS
376 XtVaGetValues((Widget) m_menuWidget,XmNnumColumns,&numColumns,NULL) ;
377 return numColumns ;
f97c9854
JS
378}
379
380void wxChoice::SetFocus()
381{
2d120f83 382 XmProcessTraversal(XtParent((Widget)m_mainWidget), XmTRAVERSE_CURRENT);
4bb6408c
JS
383}
384
bfc6fde4 385void wxChoice::DoSetSize(int x, int y, int width, int height, int sizeFlags)
4bb6408c 386{
f97c9854
JS
387 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
388 bool managed = XtIsManaged((Widget) m_formWidget);
31528cd3 389
f97c9854
JS
390 if (managed)
391 XtUnmanageChild ((Widget) m_formWidget);
31528cd3 392
3a73cc52
MB
393 int actualWidth = width - WIDTH_OVERHEAD_SUBTRACT,
394 actualHeight = height - HEIGHT_OVERHEAD;
31528cd3 395
f97c9854
JS
396 if (width > -1)
397 {
fd304d98 398 size_t i;
f97c9854 399 for (i = 0; i < m_noStrings; i++)
ec75d791
MB
400 XtVaSetValues ((Widget) m_widgetArray[i],
401 XmNwidth, actualWidth,
402 NULL);
f97c9854 403 XtVaSetValues ((Widget) m_buttonWidget, XmNwidth, actualWidth,
2d120f83 404 NULL);
f97c9854
JS
405 }
406 if (height > -1)
407 {
3a73cc52 408#if 0
fd304d98 409 size_t i;
f97c9854 410 for (i = 0; i < m_noStrings; i++)
ec75d791
MB
411 XtVaSetValues ((Widget) m_widgetArray[i],
412 XmNheight, actualHeight,
413 NULL);
3a73cc52 414#endif
f97c9854 415 XtVaSetValues ((Widget) m_buttonWidget, XmNheight, actualHeight,
2d120f83 416 NULL);
f97c9854 417 }
31528cd3 418
f97c9854
JS
419 if (managed)
420 XtManageChild ((Widget) m_formWidget);
421 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
31528cd3 422
bfc6fde4 423 wxControl::DoSetSize (x, y, width, height, sizeFlags);
4bb6408c
JS
424}
425
4bb6408c
JS
426void wxChoice::Command(wxCommandEvent & event)
427{
428 SetSelection (event.GetInt());
429 ProcessCommand (event);
430}
431
f9e02ac7 432void wxChoiceCallback (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
f97c9854
JS
433{
434 wxChoice *item = (wxChoice *) clientData;
435 if (item)
436 {
a4294b78 437 if (item->InSetValue())
f97c9854 438 return;
31528cd3 439
ec75d791
MB
440 int n = item->GetWidgets().Index(w);
441 if (n != wxNOT_FOUND)
f97c9854 442 {
ec75d791 443 wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, item->GetId());
55acd85e 444 event.SetEventObject(item);
687706f5
KH
445 event.SetInt(n);
446 event.SetString( item->GetStrings().Item(n)->GetData() );
ec75d791
MB
447 if ( item->HasClientObjectData() )
448 event.SetClientObject( item->GetClientObject(n) );
449 else if ( item->HasClientUntypedData() )
450 event.SetClientData( item->GetClientData(n) );
f97c9854
JS
451 item->ProcessCommand (event);
452 }
453 }
454}
455
4b5f3fe6 456void wxChoice::ChangeFont(bool keepOriginalSize)
0d57be45 457{
321db4b6
JS
458 // Note that this causes the widget to be resized back
459 // to its original size! We therefore have to set the size
460 // back again. TODO: a better way in Motif?
da175b2c 461 if (m_font.Ok())
321db4b6 462 {
73608949 463 Display* dpy = XtDisplay((Widget) m_mainWidget);
321db4b6
JS
464 int width, height, width1, height1;
465 GetSize(& width, & height);
31528cd3 466
da494b40
MB
467 WXString fontTag = wxFont::GetFontTag();
468
73608949
MB
469 XtVaSetValues ((Widget) m_formWidget,
470 fontTag, m_font.GetFontTypeC(dpy),
471 NULL);
472 XtVaSetValues ((Widget) m_buttonWidget,
473 fontTag, m_font.GetFontTypeC(dpy),
474 NULL);
31528cd3 475
ec75d791
MB
476 for( size_t i = 0; i < m_noStrings; ++i )
477 XtVaSetValues( (Widget)m_widgetArray[i],
73608949 478 fontTag, m_font.GetFontTypeC(dpy),
ec75d791 479 NULL );
312ebad4 480
321db4b6 481 GetSize(& width1, & height1);
4b5f3fe6 482 if (keepOriginalSize && (width != width1 || height != height1))
321db4b6 483 {
312ebad4 484 SetSize(wxDefaultCoord, wxDefaultCoord, width, height);
321db4b6
JS
485 }
486 }
0d57be45
JS
487}
488
489void wxChoice::ChangeBackgroundColour()
490{
a8680e3e
MB
491 wxDoChangeBackgroundColour(m_formWidget, m_backgroundColour);
492 wxDoChangeBackgroundColour(m_buttonWidget, m_backgroundColour);
493 wxDoChangeBackgroundColour(m_menuWidget, m_backgroundColour);
fd304d98 494 size_t i;
321db4b6 495 for (i = 0; i < m_noStrings; i++)
a8680e3e 496 wxDoChangeBackgroundColour(m_widgetArray[i], m_backgroundColour);
0d57be45
JS
497}
498
499void wxChoice::ChangeForegroundColour()
500{
a8680e3e
MB
501 wxDoChangeForegroundColour(m_formWidget, m_foregroundColour);
502 wxDoChangeForegroundColour(m_buttonWidget, m_foregroundColour);
503 wxDoChangeForegroundColour(m_menuWidget, m_foregroundColour);
fd304d98 504 size_t i;
321db4b6 505 for (i = 0; i < m_noStrings; i++)
a8680e3e 506 wxDoChangeForegroundColour(m_widgetArray[i], m_foregroundColour);
0d57be45 507}
6adaedf0 508
6adaedf0
JS
509int wxChoice::GetCount() const
510{
ec75d791 511 return m_noStrings;
6adaedf0
JS
512}
513
ec75d791 514void wxChoice::DoSetItemClientData(int n, void* clientData)
6adaedf0 515{
312ebad4 516 m_clientDataDict.Set(n, (wxClientData*)clientData, false);
6adaedf0
JS
517}
518
ec75d791 519void* wxChoice::DoGetItemClientData(int n) const
6adaedf0 520{
ec75d791 521 return (void*)m_clientDataDict.Get(n);
6adaedf0
JS
522}
523
ec75d791 524void wxChoice::DoSetItemClientObject(int n, wxClientData* clientData)
6adaedf0 525{
ec75d791 526 // don't delete, wxItemContainer does that for us
312ebad4 527 m_clientDataDict.Set(n, clientData, false);
6adaedf0
JS
528}
529
ec75d791 530wxClientData* wxChoice::DoGetItemClientObject(int n) const
6adaedf0 531{
ec75d791 532 return m_clientDataDict.Get(n);
6adaedf0
JS
533}
534
ec75d791 535void wxChoice::SetString(int WXUNUSED(n), const wxString& WXUNUSED(s))
6adaedf0 536{
ec75d791 537 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
6adaedf0
JS
538}
539
ec75d791 540wxSize wxChoice::GetItemsSize() const
6adaedf0 541{
ec75d791 542 int x, y, mx = 0, my = 0;
f6bcfd97 543
ec75d791
MB
544 // get my
545 GetTextExtent( "|", &x, &my );
f6bcfd97 546
ac32ba44 547 wxStringList::compatibility_iterator curr = m_stringList.GetFirst();
ec75d791
MB
548 while( curr )
549 {
550 GetTextExtent( curr->GetData(), &x, &y );
551 mx = wxMax( mx, x );
552 my = wxMax( my, y );
553 curr = curr->GetNext();
554 }
6adaedf0 555
ec75d791 556 return wxSize( mx, my );
6adaedf0
JS
557}
558
ec75d791 559wxSize wxChoice::DoGetBestSize() const
6adaedf0 560{
ec75d791
MB
561 wxSize items = GetItemsSize();
562 // FIXME arbitrary constants
3a73cc52
MB
563 return wxSize( ( items.x ? items.x + WIDTH_OVERHEAD : 120 ),
564 items.y + HEIGHT_OVERHEAD );
6adaedf0 565}
312ebad4
WS
566
567#endif // wxUSE_CHOICE