]> git.saurik.com Git - wxWidgets.git/blame - src/motif/choice.cpp
Honour wxSB_WRAP in wxMotif spin button
[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
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "choice.h"
14#endif
15
bcd055ae 16#ifdef __VMS
4dff3400
JJ
17#define XtDisplay XTDISPLAY
18#define XtParent XTPARENT
19#endif
20
f6045f99
GD
21#include "wx/defs.h"
22
4bb6408c 23#include "wx/choice.h"
f97c9854
JS
24#include "wx/utils.h"
25
338dd992
JJ
26#ifdef __VMS__
27#pragma message disable nosimpint
28#endif
f97c9854
JS
29#include <Xm/Xm.h>
30#include <Xm/PushBG.h>
31#include <Xm/PushB.h>
32#include <Xm/RowColumn.h>
338dd992
JJ
33#ifdef __VMS__
34#pragma message enable nosimpint
35#endif
f97c9854
JS
36
37#include "wx/motif/private.h"
4bb6408c 38
4bb6408c 39IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
4bb6408c 40
f97c9854 41void wxChoiceCallback (Widget w, XtPointer clientData,
2d120f83 42 XtPointer ptr);
f97c9854
JS
43
44wxChoice::wxChoice()
45{
46 m_noStrings = 0;
47 m_buttonWidget = (WXWidget) 0;
48 m_menuWidget = (WXWidget) 0;
49 m_widgetList = (WXWidget*) 0;
50 m_formWidget = (WXWidget) 0;
f97c9854
JS
51}
52
4bb6408c 53bool wxChoice::Create(wxWindow *parent, wxWindowID id,
2d120f83
JS
54 const wxPoint& pos,
55 const wxSize& size,
56 int n, const wxString choices[],
57 long style,
58 const wxValidator& validator,
59 const wxString& name)
4bb6408c
JS
60{
61 SetName(name);
62 SetValidator(validator);
ea57084d 63 m_noStrings = 0; // Starts off with none, incremented in Append
4bb6408c 64 m_windowStyle = style;
f97c9854
JS
65 m_buttonWidget = (WXWidget) 0;
66 m_menuWidget = (WXWidget) 0;
67 m_widgetList = (WXWidget*) 0;
68 m_formWidget = (WXWidget) 0;
31528cd3 69
4bb6408c 70 if (parent) parent->AddChild(this);
31528cd3 71
4bb6408c 72 if ( id == -1 )
2d120f83 73 m_windowId = (int)NewControlId();
4bb6408c 74 else
2d120f83 75 m_windowId = id;
31528cd3 76
0d57be45
JS
77 m_backgroundColour = parent->GetBackgroundColour();
78 m_foregroundColour = parent->GetForegroundColour();
da175b2c 79 m_font = parent->GetFont();
31528cd3 80
f97c9854 81 Widget parentWidget = (Widget) parent->GetClientWidget();
31528cd3
VZ
82
83 m_formWidget = (WXWidget) XtVaCreateManagedWidget(name.c_str(),
2d120f83
JS
84 xmRowColumnWidgetClass, parentWidget,
85 XmNmarginHeight, 0,
86 XmNmarginWidth, 0,
87 XmNpacking, XmPACK_TIGHT,
88 XmNorientation, XmHORIZONTAL,
89 NULL);
31528cd3 90
f97c9854 91 XtVaSetValues ((Widget) m_formWidget, XmNspacing, 0, NULL);
31528cd3 92
2d120f83 93 /*
f97c9854
JS
94 * Create the popup menu
95 */
96 m_menuWidget = (WXWidget) XmCreatePulldownMenu ((Widget) m_formWidget, "choiceMenu", NULL, 0);
31528cd3 97
2d120f83 98 // int i;
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
f97c9854
JS
112 XtSetArg (args[argcnt], XmNsubMenuId, (Widget) m_menuWidget);
113 argcnt++;
114 XtSetArg (args[argcnt], XmNmarginWidth, 0);
115 argcnt++;
116 XtSetArg (args[argcnt], XmNmarginHeight, 0);
117 argcnt++;
118 XtSetArg (args[argcnt], XmNpacking, XmPACK_TIGHT);
119 argcnt++;
120 m_buttonWidget = (WXWidget) XmCreateOptionMenu ((Widget) m_formWidget, "choiceButton", args, argcnt);
31528cd3 121
f97c9854 122 m_mainWidget = m_buttonWidget;
31528cd3 123
f97c9854 124 XtManageChild ((Widget) m_buttonWidget);
9838df2c 125
f97c9854
JS
126 // New code from Roland Haenel (roland_haenel@ac.cybercity.de)
127 // Some time ago, I reported a problem with wxChoice-items under
128 // Linux and Motif 2.0 (they caused sporadic GPFs). Now it seems
129 // that I have found the code responsible for this behaviour.
130#if XmVersion >= 1002
131#if XmVersion < 2000
9838df2c
JS
132 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
133 // in controls sample.
dfe1eee3
VZ
134 //
135 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
136 // XtUnmanageChild (optionLabel);
f97c9854
JS
137#endif
138#endif
9838df2c 139
f97c9854 140 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
31528cd3 141
4b5f3fe6 142 ChangeFont(FALSE);
9838df2c 143
f97c9854 144 AttachWidget (parent, m_buttonWidget, m_formWidget, pos.x, pos.y, size.x, size.y);
31528cd3 145
0d57be45 146 ChangeBackgroundColour();
31528cd3 147
f97c9854
JS
148 return TRUE;
149}
150
151wxChoice::~wxChoice()
152{
2d120f83
JS
153 // For some reason destroying the menuWidget
154 // can cause crashes on some machines. It will
155 // be deleted implicitly by deleting the parent form
156 // anyway.
157 // XtDestroyWidget (menuWidget);
f97c9854
JS
158 if (m_widgetList)
159 delete[] m_widgetList;
31528cd3 160
8aa04e8b
JS
161 if (GetMainWidget())
162 {
163 DetachWidget(GetMainWidget()); // Removes event handlers
b412f9be 164 DetachWidget(m_formWidget);
31528cd3 165
8aa04e8b
JS
166 XtDestroyWidget((Widget) m_formWidget);
167 m_formWidget = (WXWidget) 0;
31528cd3 168
8aa04e8b
JS
169 // Presumably the other widgets have been deleted now, via the form
170 m_mainWidget = (WXWidget) 0;
171 m_buttonWidget = (WXWidget) 0;
172 }
4bb6408c
JS
173}
174
c33c81c3 175int wxChoice::DoAppend(const wxString& item)
4bb6408c 176{
31528cd3 177 Widget w = XtVaCreateManagedWidget (wxStripMenuCodes(item),
f97c9854 178#if USE_GADGETS
2d120f83 179 xmPushButtonGadgetClass, (Widget) m_menuWidget,
f97c9854 180#else
2d120f83 181 xmPushButtonWidgetClass, (Widget) m_menuWidget,
f97c9854 182#endif
2d120f83 183 NULL);
31528cd3 184
2d120f83 185 DoChangeBackgroundColour((WXWidget) w, m_backgroundColour);
31528cd3 186
da175b2c 187 if (m_font.Ok())
2d120f83 188 XtVaSetValues (w,
da175b2c 189 XmNfontList, (XmFontList) m_font.GetFontList(1.0, XtDisplay((Widget) m_formWidget)),
2d120f83 190 NULL);
31528cd3 191
2d120f83
JS
192 WXWidget *new_widgetList = new WXWidget[m_noStrings + 1];
193 int i;
194 if (m_widgetList)
195 for (i = 0; i < m_noStrings; i++)
196 new_widgetList[i] = m_widgetList[i];
31528cd3 197
f6bcfd97 198 new_widgetList[m_noStrings] = (WXWidget) w;
31528cd3 199
f6bcfd97
BP
200 if (m_widgetList)
201 delete[] m_widgetList;
202 m_widgetList = new_widgetList;
31528cd3 203
f6bcfd97
BP
204 char mnem = wxFindMnemonic ((char*) (const char*) item);
205 if (mnem != 0)
206 XtVaSetValues (w, XmNmnemonic, mnem, NULL);
31528cd3 207
f6bcfd97 208 XtAddCallback (w, XmNactivateCallback, (XtCallbackProc) wxChoiceCallback, (XtPointer) this);
31528cd3 209
f6bcfd97
BP
210 if (m_noStrings == 0 && m_buttonWidget)
211 {
212 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, w, NULL);
213 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
214 XmString text = XmStringCreateSimple ((char*) (const char*) item);
215 XtVaSetValues (label,
216 XmNlabelString, text,
217 NULL);
218 XmStringFree (text);
219 }
220 wxNode *node = m_stringList.Add (item);
221 XtVaSetValues (w, XmNuserData, node->Data (), NULL);
31528cd3 222
f6bcfd97
BP
223 if (m_noStrings == 0)
224 m_clientList.Append((wxObject*) NULL);
225 else
226 m_clientList.Insert( m_clientList.Item(m_noStrings-1),
227 (wxObject*) NULL );
228 m_noStrings ++;
c33c81c3
JS
229
230 return Number() - 1;
4bb6408c
JS
231}
232
f9e02ac7 233void wxChoice::Delete(int WXUNUSED(n))
4bb6408c 234{
f97c9854 235 wxFAIL_MSG( "Sorry, wxChoice::Delete isn't implemented yet. Maybe you'd like to volunteer? :-)" );
31528cd3 236
f97c9854
JS
237 // What should we do -- remove the callback for this button widget,
238 // delete the m_stringList entry, delete the button widget, construct a new widget list
239 // (see Append)
31528cd3 240
4bb6408c
JS
241 // TODO
242 m_noStrings --;
243}
244
245void wxChoice::Clear()
246{
f97c9854
JS
247 m_stringList.Clear ();
248 int i;
249 for (i = 0; i < m_noStrings; i++)
250 {
251 XtUnmanageChild ((Widget) m_widgetList[i]);
252 XtDestroyWidget ((Widget) m_widgetList[i]);
253 }
254 if (m_noStrings)
255 delete[] m_widgetList;
256 m_widgetList = (WXWidget*) NULL;
257 if (m_buttonWidget)
258 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, (Widget) NULL, NULL);
f6bcfd97
BP
259
260 if ( HasClientObjectData() )
261 {
262 // destroy the data (due to Robert's idea of using wxList<wxObject>
263 // and not wxList<wxClientData> we can't just say
264 // m_clientList.DeleteContents(TRUE) - this would crash!
265 wxNode *node = m_clientList.First();
266 while ( node )
267 {
268 delete (wxClientData *)node->Data();
269 node = node->Next();
270 }
271 }
272 m_clientList.Clear();
273
4bb6408c
JS
274 m_noStrings = 0;
275}
276
277int wxChoice::GetSelection() const
278{
2d120f83
JS
279 XmString text;
280 char *s;
281 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
282 XtVaGetValues (label,
283 XmNlabelString, &text,
284 NULL);
31528cd3 285
2d120f83
JS
286 if (XmStringGetLtoR (text, XmSTRING_DEFAULT_CHARSET, &s))
287 {
288 int i = 0;
289 for (wxNode * node = m_stringList.First (); node; node = node->Next ())
f97c9854 290 {
2d120f83
JS
291 char *s1 = (char *) node->Data ();
292 if (s1 == s || strcmp (s1, s) == 0)
293 {
294 XmStringFree(text) ;
295 XtFree (s);
296 return i;
297 }
298 else
299 i++;
300 } // for()
31528cd3 301
2d120f83
JS
302 XmStringFree(text) ;
303 XtFree (s);
304 return -1;
305 }
306 XmStringFree(text) ;
307 return -1;
4bb6408c
JS
308}
309
310void wxChoice::SetSelection(int n)
311{
2d120f83 312 m_inSetValue = TRUE;
31528cd3 313
2d120f83
JS
314 wxNode *node = m_stringList.Nth (n);
315 if (node)
f97c9854 316 {
2d120f83 317 Dimension selectionWidth, selectionHeight;
31528cd3 318
2d120f83
JS
319 char *s = (char *) node->Data ();
320 XmString text = XmStringCreateSimple (s);
321 XtVaGetValues ((Widget) m_widgetList[n], XmNwidth, &selectionWidth, XmNheight, &selectionHeight, NULL);
322 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
323 XtVaSetValues (label,
324 XmNlabelString, text,
325 NULL);
326 XmStringFree (text);
327 XtVaSetValues ((Widget) m_buttonWidget,
328 XmNwidth, selectionWidth, XmNheight, selectionHeight,
329 XmNmenuHistory, (Widget) m_widgetList[n], NULL);
f97c9854 330 }
2d120f83 331 m_inSetValue = FALSE;
4bb6408c
JS
332}
333
334int wxChoice::FindString(const wxString& s) const
335{
f97c9854
JS
336 int i = 0;
337 for (wxNode * node = m_stringList.First (); node; node = node->Next ())
338 {
339 char *s1 = (char *) node->Data ();
340 if (s == s1)
341 {
342 return i;
343 }
344 else
345 i++;
346 }
347 return -1;
4bb6408c
JS
348}
349
350wxString wxChoice::GetString(int n) const
351{
2d120f83
JS
352 wxNode *node = m_stringList.Nth (n);
353 if (node)
354 return wxString((char *) node->Data ());
355 else
356 return wxEmptyString;
f97c9854
JS
357}
358
359void wxChoice::SetColumns(int n)
360{
2d120f83 361 if (n<1) n = 1 ;
31528cd3 362
2d120f83
JS
363 short numColumns = n ;
364 Arg args[3];
31528cd3 365
2d120f83
JS
366 XtSetArg(args[0], XmNnumColumns, numColumns);
367 XtSetArg(args[1], XmNpacking, XmPACK_COLUMN);
368 XtSetValues((Widget) m_menuWidget,args,2) ;
f97c9854
JS
369}
370
371int wxChoice::GetColumns(void) const
372{
2d120f83 373 short numColumns ;
31528cd3 374
2d120f83
JS
375 XtVaGetValues((Widget) m_menuWidget,XmNnumColumns,&numColumns,NULL) ;
376 return numColumns ;
f97c9854
JS
377}
378
379void wxChoice::SetFocus()
380{
2d120f83 381 XmProcessTraversal(XtParent((Widget)m_mainWidget), XmTRAVERSE_CURRENT);
4bb6408c
JS
382}
383
bfc6fde4 384void wxChoice::DoSetSize(int x, int y, int width, int height, int sizeFlags)
4bb6408c 385{
f97c9854
JS
386 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
387 bool managed = XtIsManaged((Widget) m_formWidget);
31528cd3 388
f97c9854
JS
389 if (managed)
390 XtUnmanageChild ((Widget) m_formWidget);
31528cd3 391
f97c9854 392 int actualWidth = width, actualHeight = height;
31528cd3 393
f97c9854
JS
394 if (width > -1)
395 {
396 int i;
397 for (i = 0; i < m_noStrings; i++)
398 XtVaSetValues ((Widget) m_widgetList[i], XmNwidth, actualWidth, NULL);
399 XtVaSetValues ((Widget) m_buttonWidget, XmNwidth, actualWidth,
2d120f83 400 NULL);
f97c9854
JS
401 }
402 if (height > -1)
403 {
404 int i;
405 for (i = 0; i < m_noStrings; i++)
406 XtVaSetValues ((Widget) m_widgetList[i], XmNheight, actualHeight, NULL);
407 XtVaSetValues ((Widget) m_buttonWidget, XmNheight, actualHeight,
2d120f83 408 NULL);
f97c9854 409 }
31528cd3 410
f97c9854
JS
411 if (managed)
412 XtManageChild ((Widget) m_formWidget);
413 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
31528cd3 414
bfc6fde4 415 wxControl::DoSetSize (x, y, width, height, sizeFlags);
4bb6408c
JS
416}
417
418wxString wxChoice::GetStringSelection () const
419{
420 int sel = GetSelection ();
421 if (sel > -1)
422 return wxString(this->GetString (sel));
423 else
f97c9854 424 return wxEmptyString;
4bb6408c
JS
425}
426
427bool wxChoice::SetStringSelection (const wxString& s)
428{
429 int sel = FindString (s);
430 if (sel > -1)
2d120f83
JS
431 {
432 SetSelection (sel);
433 return TRUE;
434 }
4bb6408c
JS
435 else
436 return FALSE;
437}
438
439void wxChoice::Command(wxCommandEvent & event)
440{
441 SetSelection (event.GetInt());
442 ProcessCommand (event);
443}
444
f9e02ac7 445void wxChoiceCallback (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
f97c9854
JS
446{
447 wxChoice *item = (wxChoice *) clientData;
448 if (item)
449 {
a4294b78 450 if (item->InSetValue())
f97c9854 451 return;
31528cd3 452
f97c9854
JS
453 char *s = NULL;
454 XtVaGetValues (w, XmNuserData, &s, NULL);
455 if (s)
456 {
55acd85e
JS
457 wxCommandEvent event (wxEVT_COMMAND_CHOICE_SELECTED, item->GetId());
458 event.SetEventObject(item);
f97c9854 459 event.m_commandInt = item->FindString (s);
2d120f83 460 // event.m_commandString = s;
f97c9854
JS
461 item->ProcessCommand (event);
462 }
463 }
464}
465
4b5f3fe6 466void wxChoice::ChangeFont(bool keepOriginalSize)
0d57be45 467{
321db4b6
JS
468 // Note that this causes the widget to be resized back
469 // to its original size! We therefore have to set the size
470 // back again. TODO: a better way in Motif?
da175b2c 471 if (m_font.Ok())
321db4b6
JS
472 {
473 int width, height, width1, height1;
474 GetSize(& width, & height);
31528cd3 475
da175b2c 476 XmFontList fontList = (XmFontList) m_font.GetFontList(1.0, XtDisplay((Widget) m_mainWidget));
321db4b6
JS
477 XtVaSetValues ((Widget) m_mainWidget, XmNfontList, fontList, NULL);
478 XtVaSetValues ((Widget) m_buttonWidget, XmNfontList, fontList, NULL);
31528cd3 479
4b5f3fe6 480 /* TODO: why does this cause a crash in XtWidgetToApplicationContext?
321db4b6
JS
481 int i;
482 for (i = 0; i < m_noStrings; i++)
2d120f83 483 XtVaSetValues ((Widget) m_widgetList[i], XmNfontList, fontList, NULL);
4b5f3fe6 484 */
321db4b6 485 GetSize(& width1, & height1);
4b5f3fe6 486 if (keepOriginalSize && (width != width1 || height != height1))
321db4b6
JS
487 {
488 SetSize(-1, -1, width, height);
489 }
490 }
0d57be45
JS
491}
492
493void wxChoice::ChangeBackgroundColour()
494{
321db4b6
JS
495 DoChangeBackgroundColour(m_formWidget, m_backgroundColour);
496 DoChangeBackgroundColour(m_buttonWidget, m_backgroundColour);
497 DoChangeBackgroundColour(m_menuWidget, m_backgroundColour);
498 int i;
499 for (i = 0; i < m_noStrings; i++)
500 DoChangeBackgroundColour(m_widgetList[i], m_backgroundColour);
0d57be45
JS
501}
502
503void wxChoice::ChangeForegroundColour()
504{
321db4b6
JS
505 DoChangeForegroundColour(m_formWidget, m_foregroundColour);
506 DoChangeForegroundColour(m_buttonWidget, m_foregroundColour);
507 DoChangeForegroundColour(m_menuWidget, m_foregroundColour);
508 int i;
509 for (i = 0; i < m_noStrings; i++)
510 DoChangeForegroundColour(m_widgetList[i], m_foregroundColour);
0d57be45 511}
6adaedf0
JS
512
513
514// These implement functions needed by wxControlWithItems.
515// Unfortunately, they're not all implemented yet.
516
517int wxChoice::GetCount() const
518{
519 return Number();
520}
521
c33c81c3 522/*
6adaedf0
JS
523int wxChoice::DoAppend(const wxString& item)
524{
525 Append(item);
526 return GetCount() - 1;
527}
c33c81c3 528*/
6adaedf0
JS
529
530// Just appends, doesn't yet insert
531void wxChoice::DoInsertItems(const wxArrayString& items, int WXUNUSED(pos))
532{
533 size_t nItems = items.GetCount();
534
535 for ( size_t n = 0; n < nItems; n++ )
536 {
537 Append( items[n]);
538 }
539}
540
541void wxChoice::DoSetItems(const wxArrayString& items, void **WXUNUSED(clientData))
542{
543 Clear();
544 size_t nItems = items.GetCount();
545
546 for ( size_t n = 0; n < nItems; n++ )
547 {
548 Append(items[n]);
549 }
550}
551
552void wxChoice::DoSetFirstItem(int WXUNUSED(n))
553{
554 wxFAIL_MSG( wxT("wxChoice::DoSetFirstItem not implemented") );
555}
556
f6bcfd97 557void wxChoice::DoSetItemClientData(int n, void* clientData)
6adaedf0 558{
f6bcfd97
BP
559 wxNode *node = m_clientList.Nth( n );
560 wxCHECK_RET( node, wxT("invalid index in wxChoice::DoSetItemClientData") );
561
562 node->SetData( (wxObject*) clientData );
6adaedf0
JS
563}
564
f6bcfd97 565void* wxChoice::DoGetItemClientData(int n) const
6adaedf0 566{
f6bcfd97
BP
567 wxNode *node = m_clientList.Nth( n );
568 wxCHECK_MSG( node, NULL, wxT("invalid index in wxChoice::DoGetItemClientData") );
569
570 return node->Data();
6adaedf0
JS
571}
572
f6bcfd97 573void wxChoice::DoSetItemClientObject(int n, wxClientData* clientData)
6adaedf0 574{
f6bcfd97
BP
575 wxNode *node = m_clientList.Nth( n );
576 wxCHECK_RET( node, wxT("invalid index in wxChoice::DoSetItemClientObject") );
577
578 wxClientData *cd = (wxClientData*) node->Data();
579 delete cd;
580
581 node->SetData( (wxObject*) clientData );
6adaedf0
JS
582}
583
f6bcfd97 584wxClientData* wxChoice::DoGetItemClientObject(int n) const
6adaedf0 585{
f6bcfd97
BP
586 wxNode *node = m_clientList.Nth( n );
587 wxCHECK_MSG( node, (wxClientData *)NULL,
588 wxT("invalid index in wxChoice::DoGetItemClientObject") );
589
590 return (wxClientData*) node->Data();
6adaedf0
JS
591}
592
593void wxChoice::Select(int n)
594{
595 SetSelection(n);
596}
597
598void wxChoice::SetString(int WXUNUSED(n), const wxString& WXUNUSED(s))
599{
600 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
601}