1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "choice.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
20 #define XtDisplay XTDISPLAY
21 #define XtParent XTPARENT
28 #include "wx/choice.h"
30 #include "wx/arrstr.h"
33 #pragma message disable nosimpint
36 #include <Xm/PushBG.h>
38 #include <Xm/RowColumn.h>
40 #pragma message enable nosimpint
43 #include "wx/motif/private.h"
45 #define WIDTH_OVERHEAD 48
46 #define WIDTH_OVERHEAD_SUBTRACT 40
47 #define HEIGHT_OVERHEAD 15
49 IMPLEMENT_DYNAMIC_CLASS(wxChoice
, wxControl
)
51 void wxChoiceCallback (Widget w
, XtPointer clientData
,
62 m_buttonWidget
= (WXWidget
) 0;
63 m_menuWidget
= (WXWidget
) 0;
64 m_formWidget
= (WXWidget
) 0;
67 bool wxChoice::Create(wxWindow
*parent
, wxWindowID id
,
70 int n
, const wxString choices
[],
72 const wxValidator
& validator
,
75 if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) )
78 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
80 m_formWidget
= (WXWidget
) XtVaCreateManagedWidget(name
.c_str(),
81 xmRowColumnWidgetClass
, parentWidget
,
84 XmNpacking
, XmPACK_TIGHT
,
85 XmNorientation
, XmHORIZONTAL
,
86 XmNresizeWidth
, False
,
87 XmNresizeHeight
, False
,
90 XtVaSetValues ((Widget
) m_formWidget
, XmNspacing
, 0, NULL
);
93 * Create the popup menu
95 m_menuWidget
= (WXWidget
) XmCreatePulldownMenu ((Widget
) m_formWidget
,
96 wxMOTIF_STR("choiceMenu"),
102 for (i
= 0; i
< n
; i
++)
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
,
117 wxMOTIF_STR("choiceButton"),
120 m_mainWidget
= m_buttonWidget
;
122 XtManageChild ((Widget
) m_buttonWidget
);
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
130 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
131 // in controls sample.
133 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
134 // XtUnmanageChild (optionLabel);
138 wxSize bestSize
= GetBestSize();
139 if( size
.x
> 0 ) bestSize
.x
= size
.x
;
140 if( size
.y
> 0 ) bestSize
.y
= size
.y
;
142 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
145 ChangeBackgroundColour();
147 AttachWidget (parent
, m_buttonWidget
, m_formWidget
,
148 pos
.x
, pos
.y
, bestSize
.x
, bestSize
.y
);
153 bool wxChoice::Create(wxWindow
*parent
, wxWindowID id
,
156 const wxArrayString
& choices
,
158 const wxValidator
& validator
,
159 const wxString
& name
)
161 wxCArrayString
chs(choices
);
162 return Create(parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(),
163 style
, validator
, name
);
166 wxChoice::~wxChoice()
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
172 // XtDestroyWidget (menuWidget);
176 DetachWidget(GetMainWidget()); // Removes event handlers
177 DetachWidget(m_formWidget
);
179 XtDestroyWidget((Widget
) m_formWidget
);
180 m_formWidget
= (WXWidget
) 0;
182 // Presumably the other widgets have been deleted now, via the form
183 m_mainWidget
= (WXWidget
) 0;
184 m_buttonWidget
= (WXWidget
) 0;
186 if ( HasClientObjectData() )
187 m_clientDataDict
.DestroyData();
190 int wxChoice::DoAppend(const wxString
& item
)
192 Widget w
= XtVaCreateManagedWidget (wxStripMenuCodes(item
),
194 xmPushButtonGadgetClass
, (Widget
) m_menuWidget
,
196 xmPushButtonWidgetClass
, (Widget
) m_menuWidget
,
200 wxDoChangeBackgroundColour((WXWidget
) w
, m_backgroundColour
);
203 wxDoChangeFont( w
, m_font
);
205 m_widgetArray
.Add(w
);
207 char mnem
= wxFindMnemonic (item
);
209 XtVaSetValues (w
, XmNmnemonic
, mnem
, NULL
);
211 XtAddCallback (w
, XmNactivateCallback
,
212 (XtCallbackProc
) wxChoiceCallback
,
215 if (m_noStrings
== 0 && m_buttonWidget
)
217 XtVaSetValues ((Widget
) m_buttonWidget
, XmNmenuHistory
, w
, NULL
);
218 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
219 wxXmString
text( item
);
220 XtVaSetValues (label
,
221 XmNlabelString
, text(),
224 m_stringList
.Add(item
);
227 return GetCount() - 1;
230 int wxChoice::DoInsert(const wxString
& item
, int pos
)
232 wxCHECK_MSG(false, -1, wxT("insert not implemented"));
234 // wxCHECK_MSG((pos>=0) && (pos<=GetCount()), -1, wxT("invalid index"));
235 // if (pos == GetCount()) return DoAppend(item);
238 void wxChoice::Delete(int n
)
240 Widget w
= (Widget
)m_widgetArray
[n
];
241 XtRemoveCallback(w
, XmNactivateCallback
, (XtCallbackProc
)wxChoiceCallback
,
243 m_stringList
.Erase(m_stringList
.Item(n
));
244 m_widgetArray
.RemoveAt(size_t(n
));
245 m_clientDataDict
.Delete(n
, HasClientObjectData());
251 void wxChoice::Clear()
253 m_stringList
.Clear ();
255 for (i
= 0; i
< m_noStrings
; i
++)
257 XtRemoveCallback((Widget
) m_widgetArray
[i
],
258 XmNactivateCallback
, (XtCallbackProc
)wxChoiceCallback
,
260 XtUnmanageChild ((Widget
) m_widgetArray
[i
]);
261 XtDestroyWidget ((Widget
) m_widgetArray
[i
]);
263 m_widgetArray
.Clear();
265 XtVaSetValues ((Widget
) m_buttonWidget
,
266 XmNmenuHistory
, (Widget
) NULL
,
269 if ( HasClientObjectData() )
270 m_clientDataDict
.DestroyData();
275 int wxChoice::GetSelection() const
278 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
279 XtVaGetValues (label
,
280 XmNlabelString
, &text
,
282 wxXmString
freeMe(text
);
283 wxString s
= wxXmStringToString( text
);
288 for (wxStringList::compatibility_iterator node
= m_stringList
.GetFirst ();
289 node
; node
= node
->GetNext ())
291 if (wxStrcmp(node
->GetData(), s
.c_str()) == 0)
304 void wxChoice::SetSelection(int n
)
308 wxStringList::compatibility_iterator node
= m_stringList
.Item(n
);
312 Dimension selectionWidth
, selectionHeight
;
314 wxXmString
text( node
->GetData() );
315 // MBN: this seems silly, at best, and causes wxChoices to be clipped:
316 // will remove "soon"
318 XtVaGetValues ((Widget
) m_widgetArray
[n
],
319 XmNwidth
, &selectionWidth
,
320 XmNheight
, &selectionHeight
,
323 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
324 XtVaSetValues (label
,
325 XmNlabelString
, text(),
328 XtVaSetValues ((Widget
) m_buttonWidget
,
329 XmNwidth
, selectionWidth
, XmNheight
, selectionHeight
,
330 XmNmenuHistory
, (Widget
) m_widgetArray
[n
], NULL
);
333 m_inSetValue
= false;
336 int wxChoice::FindString(const wxString
& s
) const
339 for (wxStringList::compatibility_iterator node
= m_stringList
.GetFirst();
340 node
; node
= node
->GetNext ())
342 if (s
== node
->GetData())
351 wxString
wxChoice::GetString(int n
) const
353 wxStringList::compatibility_iterator node
= m_stringList
.Item(n
);
355 return node
->GetData();
357 return wxEmptyString
;
360 void wxChoice::SetColumns(int n
)
364 short numColumns
= n
;
367 XtSetArg(args
[0], XmNnumColumns
, numColumns
);
368 XtSetArg(args
[1], XmNpacking
, XmPACK_COLUMN
);
369 XtSetValues((Widget
) m_menuWidget
,args
,2) ;
372 int wxChoice::GetColumns(void) const
376 XtVaGetValues((Widget
) m_menuWidget
,XmNnumColumns
,&numColumns
,NULL
) ;
380 void wxChoice::SetFocus()
382 XmProcessTraversal(XtParent((Widget
)m_mainWidget
), XmTRAVERSE_CURRENT
);
385 void wxChoice::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
387 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_ANY
, NULL
);
388 bool managed
= XtIsManaged((Widget
) m_formWidget
);
391 XtUnmanageChild ((Widget
) m_formWidget
);
393 int actualWidth
= width
- WIDTH_OVERHEAD_SUBTRACT
,
394 actualHeight
= height
- HEIGHT_OVERHEAD
;
399 for (i
= 0; i
< m_noStrings
; i
++)
400 XtVaSetValues ((Widget
) m_widgetArray
[i
],
401 XmNwidth
, actualWidth
,
403 XtVaSetValues ((Widget
) m_buttonWidget
, XmNwidth
, actualWidth
,
410 for (i
= 0; i
< m_noStrings
; i
++)
411 XtVaSetValues ((Widget
) m_widgetArray
[i
],
412 XmNheight
, actualHeight
,
415 XtVaSetValues ((Widget
) m_buttonWidget
, XmNheight
, actualHeight
,
420 XtManageChild ((Widget
) m_formWidget
);
421 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
423 wxControl::DoSetSize (x
, y
, width
, height
, sizeFlags
);
426 void wxChoice::Command(wxCommandEvent
& event
)
428 SetSelection (event
.GetInt());
429 ProcessCommand (event
);
432 void wxChoiceCallback (Widget w
, XtPointer clientData
, XtPointer
WXUNUSED(ptr
))
434 wxChoice
*item
= (wxChoice
*) clientData
;
437 if (item
->InSetValue())
440 int n
= item
->GetWidgets().Index(w
);
441 if (n
!= wxNOT_FOUND
)
443 wxCommandEvent
event(wxEVT_COMMAND_CHOICE_SELECTED
, item
->GetId());
444 event
.SetEventObject(item
);
446 event
.SetString( item
->GetStrings().Item(n
)->GetData() );
447 if ( item
->HasClientObjectData() )
448 event
.SetClientObject( item
->GetClientObject(n
) );
449 else if ( item
->HasClientUntypedData() )
450 event
.SetClientData( item
->GetClientData(n
) );
451 item
->ProcessCommand (event
);
456 void wxChoice::ChangeFont(bool keepOriginalSize
)
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?
463 Display
* dpy
= XtDisplay((Widget
) m_mainWidget
);
464 int width
, height
, width1
, height1
;
465 GetSize(& width
, & height
);
467 WXString fontTag
= wxFont::GetFontTag();
469 XtVaSetValues ((Widget
) m_formWidget
,
470 fontTag
, m_font
.GetFontTypeC(dpy
),
472 XtVaSetValues ((Widget
) m_buttonWidget
,
473 fontTag
, m_font
.GetFontTypeC(dpy
),
476 for( size_t i
= 0; i
< m_noStrings
; ++i
)
477 XtVaSetValues( (Widget
)m_widgetArray
[i
],
478 fontTag
, m_font
.GetFontTypeC(dpy
),
481 GetSize(& width1
, & height1
);
482 if (keepOriginalSize
&& (width
!= width1
|| height
!= height1
))
484 SetSize(wxDefaultCoord
, wxDefaultCoord
, width
, height
);
489 void wxChoice::ChangeBackgroundColour()
491 wxDoChangeBackgroundColour(m_formWidget
, m_backgroundColour
);
492 wxDoChangeBackgroundColour(m_buttonWidget
, m_backgroundColour
);
493 wxDoChangeBackgroundColour(m_menuWidget
, m_backgroundColour
);
495 for (i
= 0; i
< m_noStrings
; i
++)
496 wxDoChangeBackgroundColour(m_widgetArray
[i
], m_backgroundColour
);
499 void wxChoice::ChangeForegroundColour()
501 wxDoChangeForegroundColour(m_formWidget
, m_foregroundColour
);
502 wxDoChangeForegroundColour(m_buttonWidget
, m_foregroundColour
);
503 wxDoChangeForegroundColour(m_menuWidget
, m_foregroundColour
);
505 for (i
= 0; i
< m_noStrings
; i
++)
506 wxDoChangeForegroundColour(m_widgetArray
[i
], m_foregroundColour
);
509 int wxChoice::GetCount() const
514 void wxChoice::DoSetItemClientData(int n
, void* clientData
)
516 m_clientDataDict
.Set(n
, (wxClientData
*)clientData
, false);
519 void* wxChoice::DoGetItemClientData(int n
) const
521 return (void*)m_clientDataDict
.Get(n
);
524 void wxChoice::DoSetItemClientObject(int n
, wxClientData
* clientData
)
526 // don't delete, wxItemContainer does that for us
527 m_clientDataDict
.Set(n
, clientData
, false);
530 wxClientData
* wxChoice::DoGetItemClientObject(int n
) const
532 return m_clientDataDict
.Get(n
);
535 void wxChoice::SetString(int WXUNUSED(n
), const wxString
& WXUNUSED(s
))
537 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
540 wxSize
wxChoice::GetItemsSize() const
542 int x
, y
, mx
= 0, my
= 0;
545 GetTextExtent( "|", &x
, &my
);
547 wxStringList::compatibility_iterator curr
= m_stringList
.GetFirst();
550 GetTextExtent( curr
->GetData(), &x
, &y
);
553 curr
= curr
->GetNext();
556 return wxSize( mx
, my
);
559 wxSize
wxChoice::DoGetBestSize() const
561 wxSize items
= GetItemsSize();
562 // FIXME arbitrary constants
563 return wxSize( ( items
.x
? items
.x
+ WIDTH_OVERHEAD
: 120 ),
564 items
.y
+ HEIGHT_OVERHEAD
);
567 #endif // wxUSE_CHOICE