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"
17 #include "wx/choice.h"
21 #include "wx/arrstr.h"
25 #pragma message disable nosimpint
28 #include <Xm/PushBG.h>
30 #include <Xm/RowColumn.h>
32 #pragma message enable nosimpint
35 #include "wx/motif/private.h"
37 #define WIDTH_OVERHEAD 48
38 #define WIDTH_OVERHEAD_SUBTRACT 40
39 #define HEIGHT_OVERHEAD 15
41 IMPLEMENT_DYNAMIC_CLASS(wxChoice
, wxControlWithItems
)
43 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
) )
71 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
73 m_formWidget
= (WXWidget
) XtVaCreateManagedWidget(name
.c_str(),
74 xmRowColumnWidgetClass
, parentWidget
,
77 XmNpacking
, XmPACK_TIGHT
,
78 XmNorientation
, XmHORIZONTAL
,
79 XmNresizeWidth
, False
,
80 XmNresizeHeight
, False
,
83 XtVaSetValues ((Widget
) m_formWidget
, XmNspacing
, 0, NULL
);
86 * Create the popup menu
88 m_menuWidget
= (WXWidget
) XmCreatePulldownMenu ((Widget
) m_formWidget
,
89 wxMOTIF_STR("choiceMenu"),
95 for (i
= 0; i
< n
; i
++)
105 XtSetArg (args
[argcnt
], XmNsubMenuId
, (Widget
) m_menuWidget
); ++argcnt
;
106 XtSetArg (args
[argcnt
], XmNmarginWidth
, 0); ++argcnt
;
107 XtSetArg (args
[argcnt
], XmNmarginHeight
, 0); ++argcnt
;
108 XtSetArg (args
[argcnt
], XmNpacking
, XmPACK_TIGHT
); ++argcnt
;
109 m_buttonWidget
= (WXWidget
) XmCreateOptionMenu ((Widget
) m_formWidget
,
110 wxMOTIF_STR("choiceButton"),
113 m_mainWidget
= m_buttonWidget
;
115 XtManageChild ((Widget
) m_buttonWidget
);
117 // New code from Roland Haenel (roland_haenel@ac.cybercity.de)
118 // Some time ago, I reported a problem with wxChoice-items under
119 // Linux and Motif 2.0 (they caused sporadic GPFs). Now it seems
120 // that I have found the code responsible for this behaviour.
121 #if XmVersion >= 1002
123 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
124 // in controls sample.
126 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
127 // XtUnmanageChild (optionLabel);
131 wxSize bestSize
= GetBestSize();
132 if( size
.x
> 0 ) bestSize
.x
= size
.x
;
133 if( size
.y
> 0 ) bestSize
.y
= size
.y
;
135 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
138 AttachWidget (parent
, m_buttonWidget
, m_formWidget
,
139 pos
.x
, pos
.y
, bestSize
.x
, bestSize
.y
);
144 bool wxChoice::Create(wxWindow
*parent
, wxWindowID id
,
147 const wxArrayString
& choices
,
149 const wxValidator
& validator
,
150 const wxString
& name
)
152 wxCArrayString
chs(choices
);
153 return Create(parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(),
154 style
, validator
, name
);
157 wxChoice::~wxChoice()
159 // For some reason destroying the menuWidget
160 // can cause crashes on some machines. It will
161 // be deleted implicitly by deleting the parent form
163 // XtDestroyWidget (menuWidget);
167 DetachWidget(GetMainWidget()); // Removes event handlers
168 DetachWidget(m_formWidget
);
170 XtDestroyWidget((Widget
) m_formWidget
);
171 m_formWidget
= (WXWidget
) 0;
173 // Presumably the other widgets have been deleted now, via the form
174 m_mainWidget
= (WXWidget
) 0;
175 m_buttonWidget
= (WXWidget
) 0;
179 static inline wxChar
* MYcopystring(const wxChar
* s
)
181 wxChar
* copy
= new wxChar
[wxStrlen(s
) + 1];
182 return wxStrcpy(copy
, s
);
185 // TODO auto-sorting is not supported by the code
186 int wxChoice::DoInsertItems(const wxArrayStringsAdapter
& items
,
188 void **clientData
, wxClientDataType type
)
190 #ifndef XmNpositionIndex
191 wxCHECK_MSG( pos
== GetCount(), -1, wxT("insert not implemented"));
194 const unsigned int numItems
= items
.GetCount();
195 AllocClientData(numItems
);
196 for( unsigned int i
= 0; i
< numItems
; ++i
, ++pos
)
198 Widget w
= XtVaCreateManagedWidget (GetLabelText(items
[i
]),
200 xmPushButtonGadgetClass
, (Widget
) m_menuWidget
,
202 xmPushButtonWidgetClass
, (Widget
) m_menuWidget
,
204 #ifdef XmNpositionIndex
205 XmNpositionIndex
, pos
,
209 wxDoChangeBackgroundColour((WXWidget
) w
, m_backgroundColour
);
212 wxDoChangeFont( w
, m_font
);
214 m_widgetArray
.Insert(w
, pos
);
216 char mnem
= wxFindMnemonic (items
[i
]);
218 XtVaSetValues (w
, XmNmnemonic
, mnem
, NULL
);
220 XtAddCallback (w
, XmNactivateCallback
,
221 (XtCallbackProc
) wxChoiceCallback
,
224 if (m_noStrings
== 0 && m_buttonWidget
)
226 XtVaSetValues ((Widget
) m_buttonWidget
, XmNmenuHistory
, w
, NULL
);
227 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
228 wxXmString
text( items
[i
] );
229 XtVaSetValues (label
,
230 XmNlabelString
, text(),
233 // need to ditch wxStringList for wxArrayString
234 m_stringList
.Insert(pos
, MYcopystring(items
[i
]));
237 InsertNewItemClientData(pos
, clientData
, i
, type
);
243 void wxChoice::DoDeleteOneItem(unsigned int n
)
245 Widget w
= (Widget
)m_widgetArray
[n
];
246 XtRemoveCallback(w
, XmNactivateCallback
, (XtCallbackProc
)wxChoiceCallback
,
248 m_stringList
.Erase(m_stringList
.Item(n
));
249 m_widgetArray
.RemoveAt(size_t(n
));
250 wxChoiceBase::DoDeleteOneItem(n
);
256 void wxChoice::DoClear()
258 m_stringList
.Clear ();
260 for (i
= 0; i
< m_noStrings
; i
++)
262 XtRemoveCallback((Widget
) m_widgetArray
[i
],
263 XmNactivateCallback
, (XtCallbackProc
)wxChoiceCallback
,
265 XtUnmanageChild ((Widget
) m_widgetArray
[i
]);
266 XtDestroyWidget ((Widget
) m_widgetArray
[i
]);
268 m_widgetArray
.Clear();
270 XtVaSetValues ((Widget
) m_buttonWidget
,
271 XmNmenuHistory
, (Widget
) NULL
,
274 wxChoiceBase::DoClear();
279 int wxChoice::GetSelection() const
282 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
283 XtVaGetValues (label
,
284 XmNlabelString
, &text
,
286 wxXmString
freeMe(text
);
287 wxString s
= wxXmStringToString( text
);
292 for (wxStringList::compatibility_iterator node
= m_stringList
.GetFirst ();
293 node
; node
= node
->GetNext ())
295 if (wxStrcmp(node
->GetData(), s
.c_str()) == 0)
308 void wxChoice::SetSelection(int n
)
312 wxStringList::compatibility_iterator node
= m_stringList
.Item(n
);
316 Dimension selectionWidth
, selectionHeight
;
318 wxXmString
text( node
->GetData() );
319 // MBN: this seems silly, at best, and causes wxChoices to be clipped:
320 // will remove "soon"
322 XtVaGetValues ((Widget
) m_widgetArray
[n
],
323 XmNwidth
, &selectionWidth
,
324 XmNheight
, &selectionHeight
,
327 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
328 XtVaSetValues (label
,
329 XmNlabelString
, text(),
332 XtVaSetValues ((Widget
) m_buttonWidget
,
333 XmNwidth
, selectionWidth
, XmNheight
, selectionHeight
,
334 XmNmenuHistory
, (Widget
) m_widgetArray
[n
], NULL
);
337 m_inSetValue
= false;
340 wxString
wxChoice::GetString(unsigned int n
) const
342 wxStringList::compatibility_iterator node
= m_stringList
.Item(n
);
344 return node
->GetData();
346 return wxEmptyString
;
349 void wxChoice::SetColumns(int n
)
353 short numColumns
= (short)n
;
356 XtSetArg(args
[0], XmNnumColumns
, numColumns
);
357 XtSetArg(args
[1], XmNpacking
, XmPACK_COLUMN
);
358 XtSetValues((Widget
) m_menuWidget
,args
,2) ;
361 int wxChoice::GetColumns(void) const
365 XtVaGetValues((Widget
) m_menuWidget
,XmNnumColumns
,&numColumns
,NULL
) ;
369 void wxChoice::SetFocus()
371 XmProcessTraversal(XtParent((Widget
)m_mainWidget
), XmTRAVERSE_CURRENT
);
374 void wxChoice::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
376 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_ANY
, NULL
);
377 bool managed
= XtIsManaged((Widget
) m_formWidget
);
380 XtUnmanageChild ((Widget
) m_formWidget
);
382 int actualWidth
= width
- WIDTH_OVERHEAD_SUBTRACT
,
383 actualHeight
= height
- HEIGHT_OVERHEAD
;
388 for (i
= 0; i
< m_noStrings
; i
++)
389 XtVaSetValues ((Widget
) m_widgetArray
[i
],
390 XmNwidth
, actualWidth
,
392 XtVaSetValues ((Widget
) m_buttonWidget
, XmNwidth
, actualWidth
,
399 for (i
= 0; i
< m_noStrings
; i
++)
400 XtVaSetValues ((Widget
) m_widgetArray
[i
],
401 XmNheight
, actualHeight
,
404 XtVaSetValues ((Widget
) m_buttonWidget
, XmNheight
, actualHeight
,
409 XtManageChild ((Widget
) m_formWidget
);
410 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
412 wxControl::DoSetSize (x
, y
, width
, height
, sizeFlags
);
415 void wxChoice::Command(wxCommandEvent
& event
)
417 SetSelection (event
.GetInt());
418 ProcessCommand (event
);
421 void wxChoiceCallback (Widget w
, XtPointer clientData
, XtPointer
WXUNUSED(ptr
))
423 wxChoice
*item
= (wxChoice
*) clientData
;
426 if (item
->InSetValue())
429 int n
= item
->GetWidgets().Index(w
);
430 if (n
!= wxNOT_FOUND
)
432 wxCommandEvent
event(wxEVT_COMMAND_CHOICE_SELECTED
, item
->GetId());
433 event
.SetEventObject(item
);
435 event
.SetString( item
->GetStrings().Item(n
)->GetData() );
436 if ( item
->HasClientObjectData() )
437 event
.SetClientObject( item
->GetClientObject(n
) );
438 else if ( item
->HasClientUntypedData() )
439 event
.SetClientData( item
->GetClientData(n
) );
440 item
->ProcessCommand (event
);
445 void wxChoice::ChangeFont(bool keepOriginalSize
)
447 // Note that this causes the widget to be resized back
448 // to its original size! We therefore have to set the size
449 // back again. TODO: a better way in Motif?
450 if (m_mainWidget
&& m_font
.Ok())
452 Display
* dpy
= XtDisplay((Widget
) m_mainWidget
);
453 int width
, height
, width1
, height1
;
454 GetSize(& width
, & height
);
456 WXString fontTag
= wxFont::GetFontTag();
458 XtVaSetValues ((Widget
) m_formWidget
,
459 fontTag
, m_font
.GetFontTypeC(dpy
),
461 XtVaSetValues ((Widget
) m_buttonWidget
,
462 fontTag
, m_font
.GetFontTypeC(dpy
),
465 for( unsigned int i
= 0; i
< m_noStrings
; ++i
)
466 XtVaSetValues( (Widget
)m_widgetArray
[i
],
467 fontTag
, m_font
.GetFontTypeC(dpy
),
470 GetSize(& width1
, & height1
);
471 if (keepOriginalSize
&& (width
!= width1
|| height
!= height1
))
473 SetSize(wxDefaultCoord
, wxDefaultCoord
, width
, height
);
478 void wxChoice::ChangeBackgroundColour()
480 wxDoChangeBackgroundColour(m_formWidget
, m_backgroundColour
);
481 wxDoChangeBackgroundColour(m_buttonWidget
, m_backgroundColour
);
482 wxDoChangeBackgroundColour(m_menuWidget
, m_backgroundColour
);
484 for (i
= 0; i
< m_noStrings
; i
++)
485 wxDoChangeBackgroundColour(m_widgetArray
[i
], m_backgroundColour
);
488 void wxChoice::ChangeForegroundColour()
490 wxDoChangeForegroundColour(m_formWidget
, m_foregroundColour
);
491 wxDoChangeForegroundColour(m_buttonWidget
, m_foregroundColour
);
492 wxDoChangeForegroundColour(m_menuWidget
, m_foregroundColour
);
494 for (i
= 0; i
< m_noStrings
; i
++)
495 wxDoChangeForegroundColour(m_widgetArray
[i
], m_foregroundColour
);
498 unsigned int wxChoice::GetCount() const
503 void wxChoice::SetString(unsigned int WXUNUSED(n
), const wxString
& WXUNUSED(s
))
505 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
508 wxSize
wxChoice::GetItemsSize() const
510 int x
, y
, mx
= 0, my
= 0;
513 GetTextExtent( "|", &x
, &my
);
515 wxStringList::compatibility_iterator curr
= m_stringList
.GetFirst();
518 GetTextExtent( curr
->GetData(), &x
, &y
);
521 curr
= curr
->GetNext();
524 return wxSize( mx
, my
);
527 wxSize
wxChoice::DoGetBestSize() const
529 wxSize items
= GetItemsSize();
530 // FIXME arbitrary constants
531 return wxSize( ( items
.x
? items
.x
+ WIDTH_OVERHEAD
: 120 ),
532 items
.y
+ HEIGHT_OVERHEAD
);
535 #endif // wxUSE_CHOICE