]> git.saurik.com Git - wxWidgets.git/blob - src/motif/choice.cpp
Always link with expat in monolithic build.
[wxWidgets.git] / src / motif / choice.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/choice.cpp
3 // Purpose: wxChoice
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #if wxUSE_CHOICE
16
17 #include "wx/choice.h"
18
19 #ifndef WX_PRECOMP
20 #include "wx/utils.h"
21 #include "wx/arrstr.h"
22 #endif
23
24 #ifdef __VMS__
25 #pragma message disable nosimpint
26 #endif
27 #include <Xm/Xm.h>
28 #include <Xm/PushBG.h>
29 #include <Xm/PushB.h>
30 #include <Xm/RowColumn.h>
31 #ifdef __VMS__
32 #pragma message enable nosimpint
33 #endif
34
35 #include "wx/motif/private.h"
36
37 #define WIDTH_OVERHEAD 48
38 #define WIDTH_OVERHEAD_SUBTRACT 40
39 #define HEIGHT_OVERHEAD 15
40
41 void wxChoiceCallback (Widget w, XtPointer clientData,
42 XtPointer ptr);
43
44 wxChoice::wxChoice()
45 {
46 Init();
47 }
48
49 void wxChoice::Init()
50 {
51 m_buttonWidget = (WXWidget) 0;
52 m_menuWidget = (WXWidget) 0;
53 m_formWidget = (WXWidget) 0;
54 }
55
56 bool wxChoice::Create(wxWindow *parent, wxWindowID id,
57 const wxPoint& pos,
58 const wxSize& size,
59 int n, const wxString choices[],
60 long style,
61 const wxValidator& validator,
62 const wxString& name)
63 {
64 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
65 return false;
66 PreCreation();
67
68 Widget parentWidget = (Widget) parent->GetClientWidget();
69
70 m_formWidget = (WXWidget) XtVaCreateManagedWidget(name.c_str(),
71 xmRowColumnWidgetClass, parentWidget,
72 XmNmarginHeight, 0,
73 XmNmarginWidth, 0,
74 XmNpacking, XmPACK_TIGHT,
75 XmNorientation, XmHORIZONTAL,
76 XmNresizeWidth, False,
77 XmNresizeHeight, False,
78 NULL);
79
80 XtVaSetValues ((Widget) m_formWidget, XmNspacing, 0, NULL);
81
82 /*
83 * Create the popup menu
84 */
85 m_menuWidget = (WXWidget) XmCreatePulldownMenu ((Widget) m_formWidget,
86 wxMOTIF_STR("choiceMenu"),
87 NULL, 0);
88
89 if (n > 0)
90 {
91 int i;
92 for (i = 0; i < n; i++)
93 Append (choices[i]);
94 }
95
96 /*
97 * Create button
98 */
99 Arg args[10];
100 Cardinal argcnt = 0;
101
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,
107 wxMOTIF_STR("choiceButton"),
108 args, argcnt);
109
110 m_mainWidget = m_buttonWidget;
111
112 XtManageChild ((Widget) m_buttonWidget);
113
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
119 #if XmVersion < 2000
120 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
121 // in controls sample.
122 //
123 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
124 // XtUnmanageChild (optionLabel);
125 #endif
126 #endif
127
128 wxSize bestSize = GetBestSize();
129 if( size.x > 0 ) bestSize.x = size.x;
130 if( size.y > 0 ) bestSize.y = size.y;
131
132 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
133
134 PostCreation();
135 AttachWidget (parent, m_buttonWidget, m_formWidget,
136 pos.x, pos.y, bestSize.x, bestSize.y);
137
138 return true;
139 }
140
141 bool wxChoice::Create(wxWindow *parent, wxWindowID id,
142 const wxPoint& pos,
143 const wxSize& size,
144 const wxArrayString& choices,
145 long style,
146 const wxValidator& validator,
147 const wxString& name)
148 {
149 wxCArrayString chs(choices);
150 return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
151 style, validator, name);
152 }
153
154 wxChoice::~wxChoice()
155 {
156 // For some reason destroying the menuWidget
157 // can cause crashes on some machines. It will
158 // be deleted implicitly by deleting the parent form
159 // anyway.
160 // XtDestroyWidget (menuWidget);
161
162 if (GetMainWidget())
163 {
164 DetachWidget(GetMainWidget()); // Removes event handlers
165 DetachWidget(m_formWidget);
166
167 XtDestroyWidget((Widget) m_formWidget);
168 m_formWidget = (WXWidget) 0;
169
170 // Presumably the other widgets have been deleted now, via the form
171 m_mainWidget = (WXWidget) 0;
172 m_buttonWidget = (WXWidget) 0;
173 }
174 }
175
176 static inline wxChar* MYcopystring(const wxChar* s)
177 {
178 wxChar* copy = new wxChar[wxStrlen(s) + 1];
179 return wxStrcpy(copy, s);
180 }
181
182 // TODO auto-sorting is not supported by the code
183 int wxChoice::DoInsertItems(const wxArrayStringsAdapter& items,
184 unsigned int pos,
185 void **clientData, wxClientDataType type)
186 {
187 #ifndef XmNpositionIndex
188 wxCHECK_MSG( pos == GetCount(), -1, wxT("insert not implemented"));
189 #endif
190
191 const unsigned int numItems = items.GetCount();
192 AllocClientData(numItems);
193 for( unsigned int i = 0; i < numItems; ++i, ++pos )
194 {
195 Widget w = XtVaCreateManagedWidget (GetLabelText(items[i]),
196 #if wxUSE_GADGETS
197 xmPushButtonGadgetClass, (Widget) m_menuWidget,
198 #else
199 xmPushButtonWidgetClass, (Widget) m_menuWidget,
200 #endif
201 #ifdef XmNpositionIndex
202 XmNpositionIndex, pos,
203 #endif
204 NULL);
205
206 wxDoChangeBackgroundColour((WXWidget) w, m_backgroundColour);
207
208 if( m_font.IsOk() )
209 wxDoChangeFont( w, m_font );
210
211 m_widgetArray.Insert(w, pos);
212
213 char mnem = wxFindMnemonic (items[i]);
214 if (mnem != 0)
215 XtVaSetValues (w, XmNmnemonic, mnem, NULL);
216
217 XtAddCallback (w, XmNactivateCallback,
218 (XtCallbackProc) wxChoiceCallback,
219 (XtPointer) this);
220
221 if (m_stringArray.GetCount() == 0 && m_buttonWidget)
222 {
223 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, w, NULL);
224 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
225 wxXmString text( items[i] );
226 XtVaSetValues (label,
227 XmNlabelString, text(),
228 NULL);
229 }
230
231 m_stringArray.Insert(items[i], pos);
232
233 InsertNewItemClientData(pos, clientData, i, type);
234 }
235
236 return pos - 1;
237 }
238
239 void wxChoice::DoDeleteOneItem(unsigned int n)
240 {
241 Widget w = (Widget)m_widgetArray[n];
242 XtRemoveCallback(w, XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
243 (XtPointer)this);
244
245 m_stringArray.RemoveAt(size_t(n));
246 m_widgetArray.RemoveAt(size_t(n));
247 wxChoiceBase::DoDeleteOneItem(n);
248
249 XtDestroyWidget(w);
250 }
251
252 void wxChoice::DoClear()
253 {
254 m_stringArray.Clear();
255
256 unsigned int i;
257 for (i = 0; i < m_stringArray.GetCount(); i++)
258 {
259 XtRemoveCallback((Widget) m_widgetArray[i],
260 XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
261 (XtPointer)this);
262 XtUnmanageChild ((Widget) m_widgetArray[i]);
263 XtDestroyWidget ((Widget) m_widgetArray[i]);
264 }
265
266 m_widgetArray.Clear();
267 if (m_buttonWidget)
268 XtVaSetValues ((Widget) m_buttonWidget,
269 XmNmenuHistory, (Widget) NULL,
270 NULL);
271
272 wxChoiceBase::DoClear();
273 }
274
275 int wxChoice::GetSelection() const
276 {
277 XmString text;
278 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
279 XtVaGetValues (label,
280 XmNlabelString, &text,
281 NULL);
282 wxXmString freeMe(text);
283 wxString s = wxXmStringToString( text );
284
285 if (!s.empty())
286 {
287 for (size_t i=0; i<m_stringArray.GetCount(); i++)
288 if (m_stringArray[i] == s)
289 return i;
290
291 return wxNOT_FOUND;
292 }
293
294 return wxNOT_FOUND;
295 }
296
297 void wxChoice::SetSelection(int n)
298 {
299 m_inSetValue = true;
300
301 #if 0
302 Dimension selectionWidth, selectionHeight;
303 #endif
304 wxXmString text( m_stringArray[n] );
305 // MBN: this seems silly, at best, and causes wxChoices to be clipped:
306 // will remove "soon"
307 #if 0
308 XtVaGetValues ((Widget) m_widgetArray[n],
309 XmNwidth, &selectionWidth,
310 XmNheight, &selectionHeight,
311 NULL);
312 #endif
313 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
314 XtVaSetValues (label,
315 XmNlabelString, text(),
316 NULL);
317 #if 0
318 XtVaSetValues ((Widget) m_buttonWidget,
319 XmNwidth, selectionWidth, XmNheight, selectionHeight,
320 XmNmenuHistory, (Widget) m_widgetArray[n], NULL);
321 #endif
322
323 m_inSetValue = false;
324 }
325
326 wxString wxChoice::GetString(unsigned int n) const
327 {
328 return m_stringArray[n];
329 }
330
331 void wxChoice::SetColumns(int n)
332 {
333 if (n<1) n = 1 ;
334
335 short numColumns = (short)n ;
336 Arg args[3];
337
338 XtSetArg(args[0], XmNnumColumns, numColumns);
339 XtSetArg(args[1], XmNpacking, XmPACK_COLUMN);
340 XtSetValues((Widget) m_menuWidget,args,2) ;
341 }
342
343 int wxChoice::GetColumns(void) const
344 {
345 short numColumns ;
346
347 XtVaGetValues((Widget) m_menuWidget,XmNnumColumns,&numColumns,NULL) ;
348 return numColumns ;
349 }
350
351 void wxChoice::SetFocus()
352 {
353 XmProcessTraversal(XtParent((Widget)m_mainWidget), XmTRAVERSE_CURRENT);
354 }
355
356 void wxChoice::DoSetSize(int x, int y, int width, int height, int sizeFlags)
357 {
358 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
359 bool managed = XtIsManaged((Widget) m_formWidget);
360
361 if (managed)
362 XtUnmanageChild ((Widget) m_formWidget);
363
364 int actualWidth = width - WIDTH_OVERHEAD_SUBTRACT,
365 actualHeight = height - HEIGHT_OVERHEAD;
366
367 if (width > -1)
368 {
369 unsigned int i;
370 for (i = 0; i < m_stringArray.GetCount(); i++)
371 XtVaSetValues ((Widget) m_widgetArray[i],
372 XmNwidth, actualWidth,
373 NULL);
374 XtVaSetValues ((Widget) m_buttonWidget, XmNwidth, actualWidth,
375 NULL);
376 }
377 if (height > -1)
378 {
379 #if 0
380 unsigned int i;
381 for (i = 0; i < m_stringArray.GetCount(); i++)
382 XtVaSetValues ((Widget) m_widgetArray[i],
383 XmNheight, actualHeight,
384 NULL);
385 #endif
386 XtVaSetValues ((Widget) m_buttonWidget, XmNheight, actualHeight,
387 NULL);
388 }
389
390 if (managed)
391 XtManageChild ((Widget) m_formWidget);
392 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
393
394 wxControl::DoSetSize (x, y, width, height, sizeFlags);
395 }
396
397 void wxChoice::Command(wxCommandEvent & event)
398 {
399 SetSelection (event.GetInt());
400 ProcessCommand (event);
401 }
402
403 void wxChoiceCallback (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
404 {
405 wxChoice *item = (wxChoice *) clientData;
406 if (item)
407 {
408 if (item->InSetValue())
409 return;
410
411 int n = item->GetWidgets().Index(w);
412 if (n != wxNOT_FOUND)
413 {
414 wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, item->GetId());
415 event.SetEventObject(item);
416 event.SetInt(n);
417 event.SetString( item->GetStrings().Item(n) );
418 if ( item->HasClientObjectData() )
419 event.SetClientObject( item->GetClientObject(n) );
420 else if ( item->HasClientUntypedData() )
421 event.SetClientData( item->GetClientData(n) );
422 item->ProcessCommand (event);
423 }
424 }
425 }
426
427 void wxChoice::ChangeFont(bool keepOriginalSize)
428 {
429 // Note that this causes the widget to be resized back
430 // to its original size! We therefore have to set the size
431 // back again. TODO: a better way in Motif?
432 if (m_mainWidget && m_font.IsOk())
433 {
434 Display* dpy = XtDisplay((Widget) m_mainWidget);
435 int width, height, width1, height1;
436 GetSize(& width, & height);
437
438 WXString fontTag = wxFont::GetFontTag();
439
440 XtVaSetValues ((Widget) m_formWidget,
441 fontTag, m_font.GetFontTypeC(dpy),
442 NULL);
443 XtVaSetValues ((Widget) m_buttonWidget,
444 fontTag, m_font.GetFontTypeC(dpy),
445 NULL);
446
447 for( unsigned int i = 0; i < m_stringArray.GetCount(); ++i )
448 XtVaSetValues( (Widget)m_widgetArray[i],
449 fontTag, m_font.GetFontTypeC(dpy),
450 NULL );
451
452 GetSize(& width1, & height1);
453 if (keepOriginalSize && (width != width1 || height != height1))
454 {
455 SetSize(wxDefaultCoord, wxDefaultCoord, width, height);
456 }
457 }
458 }
459
460 void wxChoice::ChangeBackgroundColour()
461 {
462 wxDoChangeBackgroundColour(m_formWidget, m_backgroundColour);
463 wxDoChangeBackgroundColour(m_buttonWidget, m_backgroundColour);
464 wxDoChangeBackgroundColour(m_menuWidget, m_backgroundColour);
465 unsigned int i;
466 for (i = 0; i < m_stringArray.GetCount(); i++)
467 wxDoChangeBackgroundColour(m_widgetArray[i], m_backgroundColour);
468 }
469
470 void wxChoice::ChangeForegroundColour()
471 {
472 wxDoChangeForegroundColour(m_formWidget, m_foregroundColour);
473 wxDoChangeForegroundColour(m_buttonWidget, m_foregroundColour);
474 wxDoChangeForegroundColour(m_menuWidget, m_foregroundColour);
475 unsigned int i;
476 for (i = 0; i < m_stringArray.GetCount(); i++)
477 wxDoChangeForegroundColour(m_widgetArray[i], m_foregroundColour);
478 }
479
480 unsigned int wxChoice::GetCount() const
481 {
482 return m_stringArray.GetCount();
483 }
484
485 void wxChoice::SetString(unsigned int WXUNUSED(n), const wxString& WXUNUSED(s))
486 {
487 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
488 }
489
490 wxSize wxChoice::GetItemsSize() const
491 {
492 int x, y, mx = 0, my = 0;
493
494 // get my
495 GetTextExtent( "|", &x, &my );
496
497 for (size_t i=0; i<m_stringArray.GetCount(); i++)
498 {
499 GetTextExtent( m_stringArray[i], &x, &y );
500 mx = wxMax( mx, x );
501 my = wxMax( my, y );
502 }
503
504 return wxSize( mx, my );
505 }
506
507 wxSize wxChoice::DoGetBestSize() const
508 {
509 wxSize items = GetItemsSize();
510 // FIXME arbitrary constants
511 return wxSize( ( items.x ? items.x + WIDTH_OVERHEAD : 120 ),
512 items.y + HEIGHT_OVERHEAD );
513 }
514
515 #endif // wxUSE_CHOICE