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