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"
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 #define WIDTH_OVERHEAD 48
40 #define WIDTH_OVERHEAD_SUBTRACT 40
41 #define HEIGHT_OVERHEAD 15
43 IMPLEMENT_DYNAMIC_CLASS(wxChoice
, wxControl
)
45 void wxChoiceCallback (Widget w
, XtPointer clientData
,
58 m_buttonWidget
= (WXWidget
) 0;
59 m_menuWidget
= (WXWidget
) 0;
60 m_formWidget
= (WXWidget
) 0;
63 bool wxChoice::Create(wxWindow
*parent
, wxWindowID id
,
66 int n
, const wxString choices
[],
68 const wxValidator
& validator
,
71 if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) )
74 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
76 m_formWidget
= (WXWidget
) XtVaCreateManagedWidget(name
.c_str(),
77 xmRowColumnWidgetClass
, parentWidget
,
80 XmNpacking
, XmPACK_TIGHT
,
81 XmNorientation
, XmHORIZONTAL
,
82 XmNresizeWidth
, False
,
83 XmNresizeHeight
, False
,
86 XtVaSetValues ((Widget
) m_formWidget
, XmNspacing
, 0, NULL
);
89 * Create the popup menu
91 m_menuWidget
= (WXWidget
) XmCreatePulldownMenu ((Widget
) m_formWidget
,
92 "choiceMenu", NULL
, 0);
97 for (i
= 0; i
< n
; i
++)
107 XtSetArg (args
[argcnt
], XmNsubMenuId
, (Widget
) m_menuWidget
); ++argcnt
;
108 XtSetArg (args
[argcnt
], XmNmarginWidth
, 0); ++argcnt
;
109 XtSetArg (args
[argcnt
], XmNmarginHeight
, 0); ++argcnt
;
110 XtSetArg (args
[argcnt
], XmNpacking
, XmPACK_TIGHT
); ++argcnt
;
111 m_buttonWidget
= (WXWidget
) XmCreateOptionMenu ((Widget
) m_formWidget
,
115 m_mainWidget
= m_buttonWidget
;
117 XtManageChild ((Widget
) m_buttonWidget
);
119 // New code from Roland Haenel (roland_haenel@ac.cybercity.de)
120 // Some time ago, I reported a problem with wxChoice-items under
121 // Linux and Motif 2.0 (they caused sporadic GPFs). Now it seems
122 // that I have found the code responsible for this behaviour.
123 #if XmVersion >= 1002
125 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
126 // in controls sample.
128 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
129 // XtUnmanageChild (optionLabel);
133 wxSize bestSize
= GetBestSize();
134 if( size
.x
> 0 ) bestSize
.x
= size
.x
;
135 if( size
.y
> 0 ) bestSize
.y
= size
.y
;
137 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
140 ChangeBackgroundColour();
142 AttachWidget (parent
, m_buttonWidget
, m_formWidget
,
143 pos
.x
, pos
.y
, bestSize
.x
, bestSize
.y
);
148 wxChoice::~wxChoice()
150 // For some reason destroying the menuWidget
151 // can cause crashes on some machines. It will
152 // be deleted implicitly by deleting the parent form
154 // XtDestroyWidget (menuWidget);
158 DetachWidget(GetMainWidget()); // Removes event handlers
159 DetachWidget(m_formWidget
);
161 XtDestroyWidget((Widget
) m_formWidget
);
162 m_formWidget
= (WXWidget
) 0;
164 // Presumably the other widgets have been deleted now, via the form
165 m_mainWidget
= (WXWidget
) 0;
166 m_buttonWidget
= (WXWidget
) 0;
168 if ( HasClientObjectData() )
169 m_clientDataDict
.DestroyData();
172 int wxChoice::DoAppend(const wxString
& item
)
174 Widget w
= XtVaCreateManagedWidget (wxStripMenuCodes(item
),
176 xmPushButtonGadgetClass
, (Widget
) m_menuWidget
,
178 xmPushButtonWidgetClass
, (Widget
) m_menuWidget
,
182 wxDoChangeBackgroundColour((WXWidget
) w
, m_backgroundColour
);
185 wxDoChangeFont( w
, m_font
);
187 m_widgetArray
.Add(w
);
189 char mnem
= wxFindMnemonic (item
);
191 XtVaSetValues (w
, XmNmnemonic
, mnem
, NULL
);
193 XtAddCallback (w
, XmNactivateCallback
,
194 (XtCallbackProc
) wxChoiceCallback
,
197 if (m_noStrings
== 0 && m_buttonWidget
)
199 XtVaSetValues ((Widget
) m_buttonWidget
, XmNmenuHistory
, w
, NULL
);
200 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
201 wxXmString
text( item
);
202 XtVaSetValues (label
,
203 XmNlabelString
, text(),
206 m_stringList
.Add(item
);
209 return GetCount() - 1;
212 int wxChoice::DoInsert(const wxString
& item
, int pos
)
214 wxCHECK_MSG(FALSE
, -1, wxT("insert not implemented"));
216 // wxCHECK_MSG((pos>=0) && (pos<=GetCount()), -1, wxT("invalid index"));
217 // if (pos == GetCount()) return DoAppend(item);
220 void wxChoice::Delete(int n
)
222 Widget w
= (Widget
)m_widgetArray
[n
];
223 XtRemoveCallback(w
, XmNactivateCallback
, (XtCallbackProc
)wxChoiceCallback
,
225 m_stringList
.Erase(m_stringList
.Item(n
));
226 m_widgetArray
.RemoveAt(size_t(n
));
227 m_clientDataDict
.Delete(n
, HasClientObjectData());
233 void wxChoice::Clear()
235 m_stringList
.Clear ();
237 for (i
= 0; i
< m_noStrings
; i
++)
239 XtRemoveCallback((Widget
) m_widgetArray
[i
],
240 XmNactivateCallback
, (XtCallbackProc
)wxChoiceCallback
,
242 XtUnmanageChild ((Widget
) m_widgetArray
[i
]);
243 XtDestroyWidget ((Widget
) m_widgetArray
[i
]);
245 m_widgetArray
.Clear();
247 XtVaSetValues ((Widget
) m_buttonWidget
,
248 XmNmenuHistory
, (Widget
) NULL
,
251 if ( HasClientObjectData() )
252 m_clientDataDict
.DestroyData();
257 int wxChoice::GetSelection() const
260 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
261 XtVaGetValues (label
,
262 XmNlabelString
, &text
,
264 wxXmString
freeMe(text
);
265 wxString s
= wxXmStringToString( text
);
270 for (wxStringList::compatibility_iterator node
= m_stringList
.GetFirst ();
271 node
; node
= node
->GetNext ())
273 if (wxStrcmp(node
->GetData(), s
.c_str()) == 0)
286 void wxChoice::SetSelection(int n
)
290 wxStringList::compatibility_iterator node
= m_stringList
.Item(n
);
294 Dimension selectionWidth
, selectionHeight
;
296 wxXmString
text( node
->GetData() );
297 // MBN: this seems silly, at best, and causes wxChoices to be clipped:
298 // will remove "soon"
300 XtVaGetValues ((Widget
) m_widgetArray
[n
],
301 XmNwidth
, &selectionWidth
,
302 XmNheight
, &selectionHeight
,
305 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
306 XtVaSetValues (label
,
307 XmNlabelString
, text(),
310 XtVaSetValues ((Widget
) m_buttonWidget
,
311 XmNwidth
, selectionWidth
, XmNheight
, selectionHeight
,
312 XmNmenuHistory
, (Widget
) m_widgetArray
[n
], NULL
);
315 m_inSetValue
= FALSE
;
318 int wxChoice::FindString(const wxString
& s
) const
321 for (wxStringList::compatibility_iterator node
= m_stringList
.GetFirst();
322 node
; node
= node
->GetNext ())
324 if (s
== node
->GetData())
333 wxString
wxChoice::GetString(int n
) const
335 wxStringList::compatibility_iterator node
= m_stringList
.Item(n
);
337 return node
->GetData();
339 return wxEmptyString
;
342 void wxChoice::SetColumns(int n
)
346 short numColumns
= n
;
349 XtSetArg(args
[0], XmNnumColumns
, numColumns
);
350 XtSetArg(args
[1], XmNpacking
, XmPACK_COLUMN
);
351 XtSetValues((Widget
) m_menuWidget
,args
,2) ;
354 int wxChoice::GetColumns(void) const
358 XtVaGetValues((Widget
) m_menuWidget
,XmNnumColumns
,&numColumns
,NULL
) ;
362 void wxChoice::SetFocus()
364 XmProcessTraversal(XtParent((Widget
)m_mainWidget
), XmTRAVERSE_CURRENT
);
367 void wxChoice::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
369 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_ANY
, NULL
);
370 bool managed
= XtIsManaged((Widget
) m_formWidget
);
373 XtUnmanageChild ((Widget
) m_formWidget
);
375 int actualWidth
= width
- WIDTH_OVERHEAD_SUBTRACT
,
376 actualHeight
= height
- HEIGHT_OVERHEAD
;
381 for (i
= 0; i
< m_noStrings
; i
++)
382 XtVaSetValues ((Widget
) m_widgetArray
[i
],
383 XmNwidth
, actualWidth
,
385 XtVaSetValues ((Widget
) m_buttonWidget
, XmNwidth
, actualWidth
,
392 for (i
= 0; i
< m_noStrings
; i
++)
393 XtVaSetValues ((Widget
) m_widgetArray
[i
],
394 XmNheight
, actualHeight
,
397 XtVaSetValues ((Widget
) m_buttonWidget
, XmNheight
, actualHeight
,
402 XtManageChild ((Widget
) m_formWidget
);
403 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
405 wxControl::DoSetSize (x
, y
, width
, height
, sizeFlags
);
408 void wxChoice::Command(wxCommandEvent
& event
)
410 SetSelection (event
.GetInt());
411 ProcessCommand (event
);
414 void wxChoiceCallback (Widget w
, XtPointer clientData
, XtPointer
WXUNUSED(ptr
))
416 wxChoice
*item
= (wxChoice
*) clientData
;
419 if (item
->InSetValue())
422 int n
= item
->GetWidgets().Index(w
);
423 if (n
!= wxNOT_FOUND
)
425 wxCommandEvent
event(wxEVT_COMMAND_CHOICE_SELECTED
, item
->GetId());
426 event
.SetEventObject(item
);
427 event
.m_commandInt
= n
;
428 event
.m_commandString
= item
->GetStrings().Item(n
)->GetData();
429 if ( item
->HasClientObjectData() )
430 event
.SetClientObject( item
->GetClientObject(n
) );
431 else if ( item
->HasClientUntypedData() )
432 event
.SetClientData( item
->GetClientData(n
) );
433 item
->ProcessCommand (event
);
438 void wxChoice::ChangeFont(bool keepOriginalSize
)
440 // Note that this causes the widget to be resized back
441 // to its original size! We therefore have to set the size
442 // back again. TODO: a better way in Motif?
445 int width
, height
, width1
, height1
;
446 GetSize(& width
, & height
);
448 WXFontType fontType
=
449 m_font
.GetFontType(XtDisplay((Widget
) m_mainWidget
));
450 WXString fontTag
= wxFont::GetFontTag();
452 XtVaSetValues ((Widget
) m_formWidget
, fontTag
, fontType
, NULL
);
453 XtVaSetValues ((Widget
) m_buttonWidget
, fontTag
, fontType
, NULL
);
455 for( size_t i
= 0; i
< m_noStrings
; ++i
)
456 XtVaSetValues( (Widget
)m_widgetArray
[i
],
460 GetSize(& width1
, & height1
);
461 if (keepOriginalSize
&& (width
!= width1
|| height
!= height1
))
463 SetSize(-1, -1, width
, height
);
468 void wxChoice::ChangeBackgroundColour()
470 wxDoChangeBackgroundColour(m_formWidget
, m_backgroundColour
);
471 wxDoChangeBackgroundColour(m_buttonWidget
, m_backgroundColour
);
472 wxDoChangeBackgroundColour(m_menuWidget
, m_backgroundColour
);
474 for (i
= 0; i
< m_noStrings
; i
++)
475 wxDoChangeBackgroundColour(m_widgetArray
[i
], m_backgroundColour
);
478 void wxChoice::ChangeForegroundColour()
480 wxDoChangeForegroundColour(m_formWidget
, m_foregroundColour
);
481 wxDoChangeForegroundColour(m_buttonWidget
, m_foregroundColour
);
482 wxDoChangeForegroundColour(m_menuWidget
, m_foregroundColour
);
484 for (i
= 0; i
< m_noStrings
; i
++)
485 wxDoChangeForegroundColour(m_widgetArray
[i
], m_foregroundColour
);
488 int wxChoice::GetCount() const
493 void wxChoice::DoSetItemClientData(int n
, void* clientData
)
495 m_clientDataDict
.Set(n
, (wxClientData
*)clientData
, FALSE
);
498 void* wxChoice::DoGetItemClientData(int n
) const
500 return (void*)m_clientDataDict
.Get(n
);
503 void wxChoice::DoSetItemClientObject(int n
, wxClientData
* clientData
)
505 // don't delete, wxItemContainer does that for us
506 m_clientDataDict
.Set(n
, clientData
, FALSE
);
509 wxClientData
* wxChoice::DoGetItemClientObject(int n
) const
511 return m_clientDataDict
.Get(n
);
514 void wxChoice::SetString(int WXUNUSED(n
), const wxString
& WXUNUSED(s
))
516 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
519 wxSize
wxChoice::GetItemsSize() const
521 int x
, y
, mx
= 0, my
= 0;
524 GetTextExtent( "|", &x
, &my
);
526 wxStringList::compatibility_iterator curr
= m_stringList
.GetFirst();
529 GetTextExtent( curr
->GetData(), &x
, &y
);
532 curr
= curr
->GetNext();
535 return wxSize( mx
, my
);
538 wxSize
wxChoice::DoGetBestSize() const
540 wxSize items
= GetItemsSize();
541 // FIXME arbitrary constants
542 return wxSize( ( items
.x
? items
.x
+ WIDTH_OVERHEAD
: 120 ),
543 items
.y
+ HEIGHT_OVERHEAD
);