1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/choice.cpp
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
18 #define XtDisplay XTDISPLAY
19 #define XtParent XTPARENT
22 #include "wx/choice.h"
28 #include "wx/arrstr.h"
31 #pragma message disable nosimpint
34 #include <Xm/PushBG.h>
36 #include <Xm/RowColumn.h>
38 #pragma message enable nosimpint
41 #include "wx/motif/private.h"
43 #define WIDTH_OVERHEAD 48
44 #define WIDTH_OVERHEAD_SUBTRACT 40
45 #define HEIGHT_OVERHEAD 15
47 IMPLEMENT_DYNAMIC_CLASS(wxChoice
, wxControl
)
49 void wxChoiceCallback (Widget w
, XtPointer clientData
,
60 m_buttonWidget
= (WXWidget
) 0;
61 m_menuWidget
= (WXWidget
) 0;
62 m_formWidget
= (WXWidget
) 0;
65 bool wxChoice::Create(wxWindow
*parent
, wxWindowID id
,
68 int n
, const wxString choices
[],
70 const wxValidator
& validator
,
73 if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) )
76 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
78 m_formWidget
= (WXWidget
) XtVaCreateManagedWidget(name
.c_str(),
79 xmRowColumnWidgetClass
, parentWidget
,
82 XmNpacking
, XmPACK_TIGHT
,
83 XmNorientation
, XmHORIZONTAL
,
84 XmNresizeWidth
, False
,
85 XmNresizeHeight
, False
,
88 XtVaSetValues ((Widget
) m_formWidget
, XmNspacing
, 0, NULL
);
91 * Create the popup menu
93 m_menuWidget
= (WXWidget
) XmCreatePulldownMenu ((Widget
) m_formWidget
,
94 wxMOTIF_STR("choiceMenu"),
100 for (i
= 0; i
< n
; i
++)
110 XtSetArg (args
[argcnt
], XmNsubMenuId
, (Widget
) m_menuWidget
); ++argcnt
;
111 XtSetArg (args
[argcnt
], XmNmarginWidth
, 0); ++argcnt
;
112 XtSetArg (args
[argcnt
], XmNmarginHeight
, 0); ++argcnt
;
113 XtSetArg (args
[argcnt
], XmNpacking
, XmPACK_TIGHT
); ++argcnt
;
114 m_buttonWidget
= (WXWidget
) XmCreateOptionMenu ((Widget
) m_formWidget
,
115 wxMOTIF_STR("choiceButton"),
118 m_mainWidget
= m_buttonWidget
;
120 XtManageChild ((Widget
) m_buttonWidget
);
122 // New code from Roland Haenel (roland_haenel@ac.cybercity.de)
123 // Some time ago, I reported a problem with wxChoice-items under
124 // Linux and Motif 2.0 (they caused sporadic GPFs). Now it seems
125 // that I have found the code responsible for this behaviour.
126 #if XmVersion >= 1002
128 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
129 // in controls sample.
131 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
132 // XtUnmanageChild (optionLabel);
136 wxSize bestSize
= GetBestSize();
137 if( size
.x
> 0 ) bestSize
.x
= size
.x
;
138 if( size
.y
> 0 ) bestSize
.y
= size
.y
;
140 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
143 ChangeBackgroundColour();
145 AttachWidget (parent
, m_buttonWidget
, m_formWidget
,
146 pos
.x
, pos
.y
, bestSize
.x
, bestSize
.y
);
151 bool wxChoice::Create(wxWindow
*parent
, wxWindowID id
,
154 const wxArrayString
& choices
,
156 const wxValidator
& validator
,
157 const wxString
& name
)
159 wxCArrayString
chs(choices
);
160 return Create(parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(),
161 style
, validator
, name
);
164 wxChoice::~wxChoice()
166 // For some reason destroying the menuWidget
167 // can cause crashes on some machines. It will
168 // be deleted implicitly by deleting the parent form
170 // XtDestroyWidget (menuWidget);
174 DetachWidget(GetMainWidget()); // Removes event handlers
175 DetachWidget(m_formWidget
);
177 XtDestroyWidget((Widget
) m_formWidget
);
178 m_formWidget
= (WXWidget
) 0;
180 // Presumably the other widgets have been deleted now, via the form
181 m_mainWidget
= (WXWidget
) 0;
182 m_buttonWidget
= (WXWidget
) 0;
184 if ( HasClientObjectData() )
185 m_clientDataDict
.DestroyData();
188 static inline wxChar
* MYcopystring(const wxChar
* s
)
190 wxChar
* copy
= new wxChar
[wxStrlen(s
) + 1];
191 return wxStrcpy(copy
, s
);
194 int wxChoice::DoInsert(const wxString
& item
, unsigned int pos
)
196 #ifndef XmNpositionIndex
197 wxCHECK_MSG( pos
== GetCount(), -1, wxT("insert not implemented"));
199 Widget w
= XtVaCreateManagedWidget (wxStripMenuCodes(item
),
201 xmPushButtonGadgetClass
, (Widget
) m_menuWidget
,
203 xmPushButtonWidgetClass
, (Widget
) m_menuWidget
,
205 #ifdef XmNpositionIndex
206 XmNpositionIndex
, pos
,
210 wxDoChangeBackgroundColour((WXWidget
) w
, m_backgroundColour
);
213 wxDoChangeFont( w
, m_font
);
215 m_widgetArray
.Insert(w
, pos
);
217 char mnem
= wxFindMnemonic (item
);
219 XtVaSetValues (w
, XmNmnemonic
, mnem
, NULL
);
221 XtAddCallback (w
, XmNactivateCallback
,
222 (XtCallbackProc
) wxChoiceCallback
,
225 if (m_noStrings
== 0 && m_buttonWidget
)
227 XtVaSetValues ((Widget
) m_buttonWidget
, XmNmenuHistory
, w
, NULL
);
228 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
229 wxXmString
text( item
);
230 XtVaSetValues (label
,
231 XmNlabelString
, text(),
234 // need to ditch wxStringList for wxArrayString
235 m_stringList
.Insert(pos
, MYcopystring(item
));
241 int wxChoice::DoAppend(const wxString
& item
)
243 return DoInsert(item
, GetCount());
246 void wxChoice::Delete(unsigned int n
)
248 Widget w
= (Widget
)m_widgetArray
[n
];
249 XtRemoveCallback(w
, XmNactivateCallback
, (XtCallbackProc
)wxChoiceCallback
,
251 m_stringList
.Erase(m_stringList
.Item(n
));
252 m_widgetArray
.RemoveAt(size_t(n
));
253 m_clientDataDict
.Delete(n
, HasClientObjectData());
259 void wxChoice::Clear()
261 m_stringList
.Clear ();
263 for (i
= 0; i
< m_noStrings
; i
++)
265 XtRemoveCallback((Widget
) m_widgetArray
[i
],
266 XmNactivateCallback
, (XtCallbackProc
)wxChoiceCallback
,
268 XtUnmanageChild ((Widget
) m_widgetArray
[i
]);
269 XtDestroyWidget ((Widget
) m_widgetArray
[i
]);
271 m_widgetArray
.Clear();
273 XtVaSetValues ((Widget
) m_buttonWidget
,
274 XmNmenuHistory
, (Widget
) NULL
,
277 if ( HasClientObjectData() )
278 m_clientDataDict
.DestroyData();
283 int wxChoice::GetSelection() const
286 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
287 XtVaGetValues (label
,
288 XmNlabelString
, &text
,
290 wxXmString
freeMe(text
);
291 wxString s
= wxXmStringToString( text
);
296 for (wxStringList::compatibility_iterator node
= m_stringList
.GetFirst ();
297 node
; node
= node
->GetNext ())
299 if (wxStrcmp(node
->GetData(), s
.c_str()) == 0)
312 void wxChoice::SetSelection(int n
)
316 wxStringList::compatibility_iterator node
= m_stringList
.Item(n
);
320 Dimension selectionWidth
, selectionHeight
;
322 wxXmString
text( node
->GetData() );
323 // MBN: this seems silly, at best, and causes wxChoices to be clipped:
324 // will remove "soon"
326 XtVaGetValues ((Widget
) m_widgetArray
[n
],
327 XmNwidth
, &selectionWidth
,
328 XmNheight
, &selectionHeight
,
331 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
332 XtVaSetValues (label
,
333 XmNlabelString
, text(),
336 XtVaSetValues ((Widget
) m_buttonWidget
,
337 XmNwidth
, selectionWidth
, XmNheight
, selectionHeight
,
338 XmNmenuHistory
, (Widget
) m_widgetArray
[n
], NULL
);
341 m_inSetValue
= false;
344 wxString
wxChoice::GetString(unsigned int n
) const
346 wxStringList::compatibility_iterator node
= m_stringList
.Item(n
);
348 return node
->GetData();
350 return wxEmptyString
;
353 void wxChoice::SetColumns(int n
)
357 short numColumns
= (short)n
;
360 XtSetArg(args
[0], XmNnumColumns
, numColumns
);
361 XtSetArg(args
[1], XmNpacking
, XmPACK_COLUMN
);
362 XtSetValues((Widget
) m_menuWidget
,args
,2) ;
365 int wxChoice::GetColumns(void) const
369 XtVaGetValues((Widget
) m_menuWidget
,XmNnumColumns
,&numColumns
,NULL
) ;
373 void wxChoice::SetFocus()
375 XmProcessTraversal(XtParent((Widget
)m_mainWidget
), XmTRAVERSE_CURRENT
);
378 void wxChoice::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
380 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_ANY
, NULL
);
381 bool managed
= XtIsManaged((Widget
) m_formWidget
);
384 XtUnmanageChild ((Widget
) m_formWidget
);
386 int actualWidth
= width
- WIDTH_OVERHEAD_SUBTRACT
,
387 actualHeight
= height
- HEIGHT_OVERHEAD
;
392 for (i
= 0; i
< m_noStrings
; i
++)
393 XtVaSetValues ((Widget
) m_widgetArray
[i
],
394 XmNwidth
, actualWidth
,
396 XtVaSetValues ((Widget
) m_buttonWidget
, XmNwidth
, actualWidth
,
403 for (i
= 0; i
< m_noStrings
; i
++)
404 XtVaSetValues ((Widget
) m_widgetArray
[i
],
405 XmNheight
, actualHeight
,
408 XtVaSetValues ((Widget
) m_buttonWidget
, XmNheight
, actualHeight
,
413 XtManageChild ((Widget
) m_formWidget
);
414 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
416 wxControl::DoSetSize (x
, y
, width
, height
, sizeFlags
);
419 void wxChoice::Command(wxCommandEvent
& event
)
421 SetSelection (event
.GetInt());
422 ProcessCommand (event
);
425 void wxChoiceCallback (Widget w
, XtPointer clientData
, XtPointer
WXUNUSED(ptr
))
427 wxChoice
*item
= (wxChoice
*) clientData
;
430 if (item
->InSetValue())
433 int n
= item
->GetWidgets().Index(w
);
434 if (n
!= wxNOT_FOUND
)
436 wxCommandEvent
event(wxEVT_COMMAND_CHOICE_SELECTED
, item
->GetId());
437 event
.SetEventObject(item
);
439 event
.SetString( item
->GetStrings().Item(n
)->GetData() );
440 if ( item
->HasClientObjectData() )
441 event
.SetClientObject( item
->GetClientObject(n
) );
442 else if ( item
->HasClientUntypedData() )
443 event
.SetClientData( item
->GetClientData(n
) );
444 item
->ProcessCommand (event
);
449 void wxChoice::ChangeFont(bool keepOriginalSize
)
451 // Note that this causes the widget to be resized back
452 // to its original size! We therefore have to set the size
453 // back again. TODO: a better way in Motif?
456 Display
* dpy
= XtDisplay((Widget
) m_mainWidget
);
457 int width
, height
, width1
, height1
;
458 GetSize(& width
, & height
);
460 WXString fontTag
= wxFont::GetFontTag();
462 XtVaSetValues ((Widget
) m_formWidget
,
463 fontTag
, m_font
.GetFontTypeC(dpy
),
465 XtVaSetValues ((Widget
) m_buttonWidget
,
466 fontTag
, m_font
.GetFontTypeC(dpy
),
469 for( unsigned int i
= 0; i
< m_noStrings
; ++i
)
470 XtVaSetValues( (Widget
)m_widgetArray
[i
],
471 fontTag
, m_font
.GetFontTypeC(dpy
),
474 GetSize(& width1
, & height1
);
475 if (keepOriginalSize
&& (width
!= width1
|| height
!= height1
))
477 SetSize(wxDefaultCoord
, wxDefaultCoord
, width
, height
);
482 void wxChoice::ChangeBackgroundColour()
484 wxDoChangeBackgroundColour(m_formWidget
, m_backgroundColour
);
485 wxDoChangeBackgroundColour(m_buttonWidget
, m_backgroundColour
);
486 wxDoChangeBackgroundColour(m_menuWidget
, m_backgroundColour
);
488 for (i
= 0; i
< m_noStrings
; i
++)
489 wxDoChangeBackgroundColour(m_widgetArray
[i
], m_backgroundColour
);
492 void wxChoice::ChangeForegroundColour()
494 wxDoChangeForegroundColour(m_formWidget
, m_foregroundColour
);
495 wxDoChangeForegroundColour(m_buttonWidget
, m_foregroundColour
);
496 wxDoChangeForegroundColour(m_menuWidget
, m_foregroundColour
);
498 for (i
= 0; i
< m_noStrings
; i
++)
499 wxDoChangeForegroundColour(m_widgetArray
[i
], m_foregroundColour
);
502 unsigned int wxChoice::GetCount() const
507 void wxChoice::DoSetItemClientData(unsigned int n
, void* clientData
)
509 m_clientDataDict
.Set(n
, (wxClientData
*)clientData
, false);
512 void* wxChoice::DoGetItemClientData(unsigned int n
) const
514 return (void*)m_clientDataDict
.Get(n
);
517 void wxChoice::DoSetItemClientObject(unsigned int n
, wxClientData
* clientData
)
519 // don't delete, wxItemContainer does that for us
520 m_clientDataDict
.Set(n
, clientData
, false);
523 wxClientData
* wxChoice::DoGetItemClientObject(unsigned int n
) const
525 return m_clientDataDict
.Get(n
);
528 void wxChoice::SetString(unsigned int WXUNUSED(n
), const wxString
& WXUNUSED(s
))
530 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
533 wxSize
wxChoice::GetItemsSize() const
535 int x
, y
, mx
= 0, my
= 0;
538 GetTextExtent( "|", &x
, &my
);
540 wxStringList::compatibility_iterator curr
= m_stringList
.GetFirst();
543 GetTextExtent( curr
->GetData(), &x
, &y
);
546 curr
= curr
->GetNext();
549 return wxSize( mx
, my
);
552 wxSize
wxChoice::DoGetBestSize() const
554 wxSize items
= GetItemsSize();
555 // FIXME arbitrary constants
556 return wxSize( ( items
.x
? items
.x
+ WIDTH_OVERHEAD
: 120 ),
557 items
.y
+ HEIGHT_OVERHEAD
);
560 #endif // wxUSE_CHOICE