1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "choice.h"
17 #define XtDisplay XTDISPLAY
18 #define XtParent XTPARENT
23 #include "wx/choice.h"
27 #pragma message disable nosimpint
30 #include <Xm/PushBG.h>
32 #include <Xm/RowColumn.h>
34 #pragma message enable nosimpint
37 #include "wx/motif/private.h"
39 IMPLEMENT_DYNAMIC_CLASS(wxChoice
, wxControl
)
41 void wxChoiceCallback (Widget w
, XtPointer clientData
,
54 m_buttonWidget
= (WXWidget
) 0;
55 m_menuWidget
= (WXWidget
) 0;
56 m_formWidget
= (WXWidget
) 0;
59 bool wxChoice::Create(wxWindow
*parent
, wxWindowID id
,
62 int n
, const wxString choices
[],
64 const wxValidator
& validator
,
67 if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) )
70 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
72 m_formWidget
= (WXWidget
) XtVaCreateManagedWidget(name
.c_str(),
73 xmRowColumnWidgetClass
, parentWidget
,
76 XmNpacking
, XmPACK_TIGHT
,
77 XmNorientation
, XmHORIZONTAL
,
80 XtVaSetValues ((Widget
) m_formWidget
, XmNspacing
, 0, NULL
);
83 * Create the popup menu
85 m_menuWidget
= (WXWidget
) XmCreatePulldownMenu ((Widget
) m_formWidget
,
86 "choiceMenu", NULL
, 0);
92 for (i
= 0; i
< n
; i
++)
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
,
110 m_mainWidget
= m_buttonWidget
;
112 XtManageChild ((Widget
) m_buttonWidget
);
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
120 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
121 // in controls sample.
123 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
124 // XtUnmanageChild (optionLabel);
128 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
132 AttachWidget (parent
, m_buttonWidget
, m_formWidget
,
133 pos
.x
, pos
.y
, size
.x
, size
.y
);
135 ChangeBackgroundColour();
140 wxChoice::~wxChoice()
142 // For some reason destroying the menuWidget
143 // can cause crashes on some machines. It will
144 // be deleted implicitly by deleting the parent form
146 // XtDestroyWidget (menuWidget);
150 DetachWidget(GetMainWidget()); // Removes event handlers
151 DetachWidget(m_formWidget
);
153 XtDestroyWidget((Widget
) m_formWidget
);
154 m_formWidget
= (WXWidget
) 0;
156 // Presumably the other widgets have been deleted now, via the form
157 m_mainWidget
= (WXWidget
) 0;
158 m_buttonWidget
= (WXWidget
) 0;
160 if ( HasClientObjectData() )
161 m_clientDataDict
.DestroyData();
164 int wxChoice::DoAppend(const wxString
& item
)
166 Widget w
= XtVaCreateManagedWidget (wxStripMenuCodes(item
),
168 xmPushButtonGadgetClass
, (Widget
) m_menuWidget
,
170 xmPushButtonWidgetClass
, (Widget
) m_menuWidget
,
174 DoChangeBackgroundColour((WXWidget
) w
, m_backgroundColour
);
178 XmNfontList
, (XmFontList
) m_font
.GetFontList(1.0, XtDisplay((Widget
) m_formWidget
)),
181 m_widgetArray
.Add(w
);
183 char mnem
= wxFindMnemonic ((char*) (const char*) item
);
185 XtVaSetValues (w
, XmNmnemonic
, mnem
, NULL
);
187 XtAddCallback (w
, XmNactivateCallback
,
188 (XtCallbackProc
) wxChoiceCallback
,
191 if (m_noStrings
== 0 && m_buttonWidget
)
193 XtVaSetValues ((Widget
) m_buttonWidget
, XmNmenuHistory
, w
, NULL
);
194 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
195 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
196 XtVaSetValues (label
,
197 XmNlabelString
, text
,
201 m_stringList
.Add(item
);
204 return GetCount() - 1;
207 void wxChoice::Delete(int n
)
209 Widget w
= (Widget
)m_widgetArray
[n
];
210 XtRemoveCallback(w
, XmNactivateCallback
, (XtCallbackProc
)wxChoiceCallback
,
212 m_stringList
.DeleteNode(m_stringList
.Item(n
));
213 m_widgetArray
.RemoveAt(size_t(n
));
214 m_clientDataDict
.Delete(n
, HasClientObjectData());
220 void wxChoice::Clear()
222 m_stringList
.Clear ();
224 for (i
= 0; i
< m_noStrings
; i
++)
226 XtRemoveCallback((Widget
) m_widgetArray
[i
],
227 XmNactivateCallback
, (XtCallbackProc
)wxChoiceCallback
,
229 XtUnmanageChild ((Widget
) m_widgetArray
[i
]);
230 XtDestroyWidget ((Widget
) m_widgetArray
[i
]);
232 m_widgetArray
.Clear();
234 XtVaSetValues ((Widget
) m_buttonWidget
,
235 XmNmenuHistory
, (Widget
) NULL
,
238 if ( HasClientObjectData() )
239 m_clientDataDict
.DestroyData();
244 int wxChoice::GetSelection() const
248 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
249 XtVaGetValues (label
,
250 XmNlabelString
, &text
,
253 if (XmStringGetLtoR (text
, XmSTRING_DEFAULT_CHARSET
, &s
))
256 for (wxStringListNode
* node
= m_stringList
.GetFirst ();
257 node
; node
= node
->GetNext ())
259 if (strcmp(node
->GetData(), s
) == 0)
277 void wxChoice::SetSelection(int n
)
281 wxStringListNode
*node
= m_stringList
.Item(n
);
285 Dimension selectionWidth
, selectionHeight
;
287 wxXmString
text( (char*)node
->Data() );
288 // MBN: this seems silly, at best, and causes wxChoices to be clipped:
289 // will remove "soon"
291 XtVaGetValues ((Widget
) m_widgetArray
[n
],
292 XmNwidth
, &selectionWidth
,
293 XmNheight
, &selectionHeight
,
296 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
297 XtVaSetValues (label
,
298 XmNlabelString
, text(),
301 XtVaSetValues ((Widget
) m_buttonWidget
,
302 XmNwidth
, selectionWidth
, XmNheight
, selectionHeight
,
303 XmNmenuHistory
, (Widget
) m_widgetArray
[n
], NULL
);
306 m_inSetValue
= FALSE
;
309 int wxChoice::FindString(const wxString
& s
) const
312 for (wxStringListNode
* node
= m_stringList
.GetFirst();
313 node
; node
= node
->GetNext ())
315 if (s
== node
->GetData())
324 wxString
wxChoice::GetString(int n
) const
326 wxStringListNode
*node
= m_stringList
.Item(n
);
328 return node
->GetData();
330 return wxEmptyString
;
333 void wxChoice::SetColumns(int n
)
337 short numColumns
= n
;
340 XtSetArg(args
[0], XmNnumColumns
, numColumns
);
341 XtSetArg(args
[1], XmNpacking
, XmPACK_COLUMN
);
342 XtSetValues((Widget
) m_menuWidget
,args
,2) ;
345 int wxChoice::GetColumns(void) const
349 XtVaGetValues((Widget
) m_menuWidget
,XmNnumColumns
,&numColumns
,NULL
) ;
353 void wxChoice::SetFocus()
355 XmProcessTraversal(XtParent((Widget
)m_mainWidget
), XmTRAVERSE_CURRENT
);
358 void wxChoice::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
360 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_ANY
, NULL
);
361 bool managed
= XtIsManaged((Widget
) m_formWidget
);
364 XtUnmanageChild ((Widget
) m_formWidget
);
366 int actualWidth
= width
, actualHeight
= height
;
371 for (i
= 0; i
< m_noStrings
; i
++)
372 XtVaSetValues ((Widget
) m_widgetArray
[i
],
373 XmNwidth
, actualWidth
,
375 XtVaSetValues ((Widget
) m_buttonWidget
, XmNwidth
, actualWidth
,
381 for (i
= 0; i
< m_noStrings
; i
++)
382 XtVaSetValues ((Widget
) m_widgetArray
[i
],
383 XmNheight
, actualHeight
,
385 XtVaSetValues ((Widget
) m_buttonWidget
, XmNheight
, actualHeight
,
390 XtManageChild ((Widget
) m_formWidget
);
391 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
393 wxControl::DoSetSize (x
, y
, width
, height
, sizeFlags
);
396 void wxChoice::Command(wxCommandEvent
& event
)
398 SetSelection (event
.GetInt());
399 ProcessCommand (event
);
402 void wxChoiceCallback (Widget w
, XtPointer clientData
, XtPointer
WXUNUSED(ptr
))
404 wxChoice
*item
= (wxChoice
*) clientData
;
407 if (item
->InSetValue())
410 int n
= item
->GetWidgets().Index(w
);
411 if (n
!= wxNOT_FOUND
)
413 wxCommandEvent
event(wxEVT_COMMAND_CHOICE_SELECTED
, item
->GetId());
414 event
.SetEventObject(item
);
415 event
.m_commandInt
= n
;
416 event
.m_commandString
= item
->GetStrings().Item(n
)->GetData();
417 if ( item
->HasClientObjectData() )
418 event
.SetClientObject( item
->GetClientObject(n
) );
419 else if ( item
->HasClientUntypedData() )
420 event
.SetClientData( item
->GetClientData(n
) );
421 item
->ProcessCommand (event
);
426 void wxChoice::ChangeFont(bool keepOriginalSize
)
428 // Note that this causes the widget to be resized back
429 // to its original size! We therefore have to set the size
430 // back again. TODO: a better way in Motif?
433 int width
, height
, width1
, height1
;
434 GetSize(& width
, & height
);
436 XmFontList fontList
= (XmFontList
) m_font
.GetFontList(1.0, XtDisplay((Widget
) m_mainWidget
));
437 XtVaSetValues ((Widget
) m_formWidget
, XmNfontList
, fontList
, NULL
);
438 XtVaSetValues ((Widget
) m_buttonWidget
, XmNfontList
, fontList
, NULL
);
440 for( size_t i
= 0; i
< m_noStrings
; ++i
)
441 XtVaSetValues( (Widget
)m_widgetArray
[i
],
442 XmNfontList
, fontList
,
445 GetSize(& width1
, & height1
);
446 if (keepOriginalSize
&& (width
!= width1
|| height
!= height1
))
448 SetSize(-1, -1, width
, height
);
453 void wxChoice::ChangeBackgroundColour()
455 DoChangeBackgroundColour(m_formWidget
, m_backgroundColour
);
456 DoChangeBackgroundColour(m_buttonWidget
, m_backgroundColour
);
457 DoChangeBackgroundColour(m_menuWidget
, m_backgroundColour
);
459 for (i
= 0; i
< m_noStrings
; i
++)
460 DoChangeBackgroundColour(m_widgetArray
[i
], m_backgroundColour
);
463 void wxChoice::ChangeForegroundColour()
465 DoChangeForegroundColour(m_formWidget
, m_foregroundColour
);
466 DoChangeForegroundColour(m_buttonWidget
, m_foregroundColour
);
467 DoChangeForegroundColour(m_menuWidget
, m_foregroundColour
);
469 for (i
= 0; i
< m_noStrings
; i
++)
470 DoChangeForegroundColour(m_widgetArray
[i
], m_foregroundColour
);
473 int wxChoice::GetCount() const
478 void wxChoice::DoSetItemClientData(int n
, void* clientData
)
480 m_clientDataDict
.Set(n
, (wxClientData
*)clientData
, FALSE
);
483 void* wxChoice::DoGetItemClientData(int n
) const
485 return (void*)m_clientDataDict
.Get(n
);
488 void wxChoice::DoSetItemClientObject(int n
, wxClientData
* clientData
)
490 // don't delete, wxItemContainer does that for us
491 m_clientDataDict
.Set(n
, clientData
, FALSE
);
494 wxClientData
* wxChoice::DoGetItemClientObject(int n
) const
496 return m_clientDataDict
.Get(n
);
499 void wxChoice::SetString(int WXUNUSED(n
), const wxString
& WXUNUSED(s
))
501 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
504 wxSize
wxChoice::GetItemsSize() const
506 int x
, y
, mx
= 0, my
= 0;
509 GetTextExtent( "|", &x
, &my
);
511 wxStringList::Node
* curr
= m_stringList
.GetFirst();
514 GetTextExtent( curr
->GetData(), &x
, &y
);
517 curr
= curr
->GetNext();
520 return wxSize( mx
, my
);
523 wxSize
wxChoice::DoGetBestSize() const
525 wxSize items
= GetItemsSize();
526 // FIXME arbitrary constants
527 return wxSize( ( items
.x
? items
.x
+ 50 : 120 ),