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