Committing in .
[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 #ifdef __GNUG__
13 #pragma implementation "choice.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/choice.h"
18 #include "wx/utils.h"
19
20 #ifdef __VMS__
21 #pragma message disable nosimpint
22 #endif
23 #include <Xm/Xm.h>
24 #include <Xm/PushBG.h>
25 #include <Xm/PushB.h>
26 #include <Xm/RowColumn.h>
27 #ifdef __VMS__
28 #pragma message enable nosimpint
29 #endif
30
31 #include "wx/motif/private.h"
32
33 #if !USE_SHARED_LIBRARY
34 IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
35 #endif
36
37 void wxChoiceCallback (Widget w, XtPointer clientData,
38 XtPointer ptr);
39
40 wxChoice::wxChoice()
41 {
42 m_noStrings = 0;
43 m_buttonWidget = (WXWidget) 0;
44 m_menuWidget = (WXWidget) 0;
45 m_widgetList = (WXWidget*) 0;
46 m_formWidget = (WXWidget) 0;
47 }
48
49 bool wxChoice::Create(wxWindow *parent, wxWindowID id,
50 const wxPoint& pos,
51 const wxSize& size,
52 int n, const wxString choices[],
53 long style,
54 const wxValidator& validator,
55 const wxString& name)
56 {
57 SetName(name);
58 SetValidator(validator);
59 m_noStrings = 0; // Starts off with none, incremented in Append
60 m_windowStyle = style;
61 m_buttonWidget = (WXWidget) 0;
62 m_menuWidget = (WXWidget) 0;
63 m_widgetList = (WXWidget*) 0;
64 m_formWidget = (WXWidget) 0;
65
66 if (parent) parent->AddChild(this);
67
68 if ( id == -1 )
69 m_windowId = (int)NewControlId();
70 else
71 m_windowId = id;
72
73 m_backgroundColour = parent->GetBackgroundColour();
74 m_foregroundColour = parent->GetForegroundColour();
75 m_font = parent->GetFont();
76
77 Widget parentWidget = (Widget) parent->GetClientWidget();
78
79 m_formWidget = (WXWidget) XtVaCreateManagedWidget(name.c_str(),
80 xmRowColumnWidgetClass, parentWidget,
81 XmNmarginHeight, 0,
82 XmNmarginWidth, 0,
83 XmNpacking, XmPACK_TIGHT,
84 XmNorientation, XmHORIZONTAL,
85 NULL);
86
87 XtVaSetValues ((Widget) m_formWidget, XmNspacing, 0, NULL);
88
89 /*
90 * Create the popup menu
91 */
92 m_menuWidget = (WXWidget) XmCreatePulldownMenu ((Widget) m_formWidget, "choiceMenu", NULL, 0);
93
94 // int i;
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);
109 argcnt++;
110 XtSetArg (args[argcnt], XmNmarginWidth, 0);
111 argcnt++;
112 XtSetArg (args[argcnt], XmNmarginHeight, 0);
113 argcnt++;
114 XtSetArg (args[argcnt], XmNpacking, XmPACK_TIGHT);
115 argcnt++;
116 m_buttonWidget = (WXWidget) XmCreateOptionMenu ((Widget) m_formWidget, "choiceButton", args, argcnt);
117
118 m_mainWidget = m_buttonWidget;
119
120 XtManageChild ((Widget) m_buttonWidget);
121
122 // New code from Roland Haenel (roland_haenel@ac.cybercity.de)
123 // Some time ago, I reported a problem with wxChoice-items under
124 // Linux and Motif 2.0 (they caused sporadic GPFs). Now it seems
125 // that I have found the code responsible for this behaviour.
126 #if XmVersion >= 1002
127 #if XmVersion < 2000
128 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
129 // in controls sample.
130 //
131 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
132 // XtUnmanageChild (optionLabel);
133 #endif
134 #endif
135
136 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
137
138 ChangeFont(FALSE);
139
140 AttachWidget (parent, m_buttonWidget, m_formWidget, pos.x, pos.y, size.x, size.y);
141
142 ChangeBackgroundColour();
143
144 return TRUE;
145 }
146
147 wxChoice::~wxChoice()
148 {
149 // For some reason destroying the menuWidget
150 // can cause crashes on some machines. It will
151 // be deleted implicitly by deleting the parent form
152 // anyway.
153 // XtDestroyWidget (menuWidget);
154 if (m_widgetList)
155 delete[] m_widgetList;
156
157 if (GetMainWidget())
158 {
159 DetachWidget(GetMainWidget()); // Removes event handlers
160 DetachWidget(m_formWidget);
161
162 XtDestroyWidget((Widget) m_formWidget);
163 m_formWidget = (WXWidget) 0;
164
165 // Presumably the other widgets have been deleted now, via the form
166 m_mainWidget = (WXWidget) 0;
167 m_buttonWidget = (WXWidget) 0;
168 }
169 }
170
171 void wxChoice::Append(const wxString& item)
172 {
173 Widget w = XtVaCreateManagedWidget (wxStripMenuCodes(item),
174 #if USE_GADGETS
175 xmPushButtonGadgetClass, (Widget) m_menuWidget,
176 #else
177 xmPushButtonWidgetClass, (Widget) m_menuWidget,
178 #endif
179 NULL);
180
181 DoChangeBackgroundColour((WXWidget) w, m_backgroundColour);
182
183 if (m_font.Ok())
184 XtVaSetValues (w,
185 XmNfontList, (XmFontList) m_font.GetFontList(1.0, XtDisplay((Widget) m_formWidget)),
186 NULL);
187
188 WXWidget *new_widgetList = new WXWidget[m_noStrings + 1];
189 int i;
190 if (m_widgetList)
191 for (i = 0; i < m_noStrings; i++)
192 new_widgetList[i] = m_widgetList[i];
193
194 new_widgetList[m_noStrings] = (WXWidget) w;
195
196 if (m_widgetList)
197 delete[] m_widgetList;
198 m_widgetList = new_widgetList;
199
200 char mnem = wxFindMnemonic ((char*) (const char*) item);
201 if (mnem != 0)
202 XtVaSetValues (w, XmNmnemonic, mnem, NULL);
203
204 XtAddCallback (w, XmNactivateCallback, (XtCallbackProc) wxChoiceCallback, (XtPointer) this);
205
206 if (m_noStrings == 0 && m_buttonWidget)
207 {
208 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, w, NULL);
209 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
210 XmString text = XmStringCreateSimple ((char*) (const char*) item);
211 XtVaSetValues (label,
212 XmNlabelString, text,
213 NULL);
214 XmStringFree (text);
215 }
216 wxNode *node = m_stringList.Add (item);
217 XtVaSetValues (w, XmNuserData, node->Data (), NULL);
218
219 m_noStrings ++;
220 }
221
222 void wxChoice::Delete(int WXUNUSED(n))
223 {
224 wxFAIL_MSG( "Sorry, wxChoice::Delete isn't implemented yet. Maybe you'd like to volunteer? :-)" );
225
226 // What should we do -- remove the callback for this button widget,
227 // delete the m_stringList entry, delete the button widget, construct a new widget list
228 // (see Append)
229
230 // TODO
231 m_noStrings --;
232 }
233
234 void wxChoice::Clear()
235 {
236 m_stringList.Clear ();
237 int i;
238 for (i = 0; i < m_noStrings; i++)
239 {
240 XtUnmanageChild ((Widget) m_widgetList[i]);
241 XtDestroyWidget ((Widget) m_widgetList[i]);
242 }
243 if (m_noStrings)
244 delete[] m_widgetList;
245 m_widgetList = (WXWidget*) NULL;
246 if (m_buttonWidget)
247 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, (Widget) NULL, NULL);
248 m_noStrings = 0;
249 }
250
251 int wxChoice::GetSelection() const
252 {
253 XmString text;
254 char *s;
255 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
256 XtVaGetValues (label,
257 XmNlabelString, &text,
258 NULL);
259
260 if (XmStringGetLtoR (text, XmSTRING_DEFAULT_CHARSET, &s))
261 {
262 int i = 0;
263 for (wxNode * node = m_stringList.First (); node; node = node->Next ())
264 {
265 char *s1 = (char *) node->Data ();
266 if (s1 == s || strcmp (s1, s) == 0)
267 {
268 XmStringFree(text) ;
269 XtFree (s);
270 return i;
271 }
272 else
273 i++;
274 } // for()
275
276 XmStringFree(text) ;
277 XtFree (s);
278 return -1;
279 }
280 XmStringFree(text) ;
281 return -1;
282 }
283
284 void wxChoice::SetSelection(int n)
285 {
286 m_inSetValue = TRUE;
287
288 wxNode *node = m_stringList.Nth (n);
289 if (node)
290 {
291 Dimension selectionWidth, selectionHeight;
292
293 char *s = (char *) node->Data ();
294 XmString text = XmStringCreateSimple (s);
295 XtVaGetValues ((Widget) m_widgetList[n], XmNwidth, &selectionWidth, XmNheight, &selectionHeight, NULL);
296 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
297 XtVaSetValues (label,
298 XmNlabelString, text,
299 NULL);
300 XmStringFree (text);
301 XtVaSetValues ((Widget) m_buttonWidget,
302 XmNwidth, selectionWidth, XmNheight, selectionHeight,
303 XmNmenuHistory, (Widget) m_widgetList[n], NULL);
304 }
305 m_inSetValue = FALSE;
306 }
307
308 int wxChoice::FindString(const wxString& s) const
309 {
310 int i = 0;
311 for (wxNode * node = m_stringList.First (); node; node = node->Next ())
312 {
313 char *s1 = (char *) node->Data ();
314 if (s == s1)
315 {
316 return i;
317 }
318 else
319 i++;
320 }
321 return -1;
322 }
323
324 wxString wxChoice::GetString(int n) const
325 {
326 wxNode *node = m_stringList.Nth (n);
327 if (node)
328 return wxString((char *) node->Data ());
329 else
330 return wxEmptyString;
331 }
332
333 void wxChoice::SetColumns(int n)
334 {
335 if (n<1) n = 1 ;
336
337 short numColumns = n ;
338 Arg args[3];
339
340 XtSetArg(args[0], XmNnumColumns, numColumns);
341 XtSetArg(args[1], XmNpacking, XmPACK_COLUMN);
342 XtSetValues((Widget) m_menuWidget,args,2) ;
343 }
344
345 int wxChoice::GetColumns(void) const
346 {
347 short numColumns ;
348
349 XtVaGetValues((Widget) m_menuWidget,XmNnumColumns,&numColumns,NULL) ;
350 return numColumns ;
351 }
352
353 void wxChoice::SetFocus()
354 {
355 XmProcessTraversal(XtParent((Widget)m_mainWidget), XmTRAVERSE_CURRENT);
356 }
357
358 void wxChoice::DoSetSize(int x, int y, int width, int height, int sizeFlags)
359 {
360 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
361 bool managed = XtIsManaged((Widget) m_formWidget);
362
363 if (managed)
364 XtUnmanageChild ((Widget) m_formWidget);
365
366 int actualWidth = width, actualHeight = height;
367
368 if (width > -1)
369 {
370 int i;
371 for (i = 0; i < m_noStrings; i++)
372 XtVaSetValues ((Widget) m_widgetList[i], XmNwidth, actualWidth, NULL);
373 XtVaSetValues ((Widget) m_buttonWidget, XmNwidth, actualWidth,
374 NULL);
375 }
376 if (height > -1)
377 {
378 int i;
379 for (i = 0; i < m_noStrings; i++)
380 XtVaSetValues ((Widget) m_widgetList[i], XmNheight, actualHeight, NULL);
381 XtVaSetValues ((Widget) m_buttonWidget, XmNheight, actualHeight,
382 NULL);
383 }
384
385 if (managed)
386 XtManageChild ((Widget) m_formWidget);
387 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
388
389 wxControl::DoSetSize (x, y, width, height, sizeFlags);
390 }
391
392 wxString wxChoice::GetStringSelection () const
393 {
394 int sel = GetSelection ();
395 if (sel > -1)
396 return wxString(this->GetString (sel));
397 else
398 return wxEmptyString;
399 }
400
401 bool wxChoice::SetStringSelection (const wxString& s)
402 {
403 int sel = FindString (s);
404 if (sel > -1)
405 {
406 SetSelection (sel);
407 return TRUE;
408 }
409 else
410 return FALSE;
411 }
412
413 void wxChoice::Command(wxCommandEvent & event)
414 {
415 SetSelection (event.GetInt());
416 ProcessCommand (event);
417 }
418
419 void wxChoiceCallback (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
420 {
421 wxChoice *item = (wxChoice *) clientData;
422 if (item)
423 {
424 if (item->InSetValue())
425 return;
426
427 char *s = NULL;
428 XtVaGetValues (w, XmNuserData, &s, NULL);
429 if (s)
430 {
431 wxCommandEvent event (wxEVT_COMMAND_CHOICE_SELECTED, item->GetId());
432 event.SetEventObject(item);
433 event.m_commandInt = item->FindString (s);
434 // event.m_commandString = s;
435 item->ProcessCommand (event);
436 }
437 }
438 }
439
440 void wxChoice::ChangeFont(bool keepOriginalSize)
441 {
442 // Note that this causes the widget to be resized back
443 // to its original size! We therefore have to set the size
444 // back again. TODO: a better way in Motif?
445 if (m_font.Ok())
446 {
447 int width, height, width1, height1;
448 GetSize(& width, & height);
449
450 XmFontList fontList = (XmFontList) m_font.GetFontList(1.0, XtDisplay((Widget) m_mainWidget));
451 XtVaSetValues ((Widget) m_mainWidget, XmNfontList, fontList, NULL);
452 XtVaSetValues ((Widget) m_buttonWidget, XmNfontList, fontList, NULL);
453
454 /* TODO: why does this cause a crash in XtWidgetToApplicationContext?
455 int i;
456 for (i = 0; i < m_noStrings; i++)
457 XtVaSetValues ((Widget) m_widgetList[i], XmNfontList, fontList, NULL);
458 */
459 GetSize(& width1, & height1);
460 if (keepOriginalSize && (width != width1 || height != height1))
461 {
462 SetSize(-1, -1, width, height);
463 }
464 }
465 }
466
467 void wxChoice::ChangeBackgroundColour()
468 {
469 DoChangeBackgroundColour(m_formWidget, m_backgroundColour);
470 DoChangeBackgroundColour(m_buttonWidget, m_backgroundColour);
471 DoChangeBackgroundColour(m_menuWidget, m_backgroundColour);
472 int i;
473 for (i = 0; i < m_noStrings; i++)
474 DoChangeBackgroundColour(m_widgetList[i], m_backgroundColour);
475 }
476
477 void wxChoice::ChangeForegroundColour()
478 {
479 DoChangeForegroundColour(m_formWidget, m_foregroundColour);
480 DoChangeForegroundColour(m_buttonWidget, m_foregroundColour);
481 DoChangeForegroundColour(m_menuWidget, m_foregroundColour);
482 int i;
483 for (i = 0; i < m_noStrings; i++)
484 DoChangeForegroundColour(m_widgetList[i], m_foregroundColour);
485 }
486
487
488 // These implement functions needed by wxControlWithItems.
489 // Unfortunately, they're not all implemented yet.
490
491 int wxChoice::GetCount() const
492 {
493 return Number();
494 }
495
496 int wxChoice::DoAppend(const wxString& item)
497 {
498 Append(item);
499 return GetCount() - 1;
500 }
501
502 // Just appends, doesn't yet insert
503 void wxChoice::DoInsertItems(const wxArrayString& items, int WXUNUSED(pos))
504 {
505 size_t nItems = items.GetCount();
506
507 for ( size_t n = 0; n < nItems; n++ )
508 {
509 Append( items[n]);
510 }
511 }
512
513 void wxChoice::DoSetItems(const wxArrayString& items, void **WXUNUSED(clientData))
514 {
515 Clear();
516 size_t nItems = items.GetCount();
517
518 for ( size_t n = 0; n < nItems; n++ )
519 {
520 Append(items[n]);
521 }
522 }
523
524 void wxChoice::DoSetFirstItem(int WXUNUSED(n))
525 {
526 wxFAIL_MSG( wxT("wxChoice::DoSetFirstItem not implemented") );
527 }
528
529 void wxChoice::DoSetItemClientData(int WXUNUSED(n), void* WXUNUSED(clientData))
530 {
531 wxFAIL_MSG( wxT("wxChoice::DoSetItemClientData not implemented") );
532 }
533
534 void* wxChoice::DoGetItemClientData(int WXUNUSED(n)) const
535 {
536 wxFAIL_MSG( wxT("wxChoice::DoGetItemClientData not implemented") );
537 return (void*) NULL;
538 }
539
540 void wxChoice::DoSetItemClientObject(int WXUNUSED(n), wxClientData* WXUNUSED(clientData))
541 {
542 wxFAIL_MSG( wxT("wxChoice::DoSetItemClientObject not implemented") );
543 }
544
545 wxClientData* wxChoice::DoGetItemClientObject(int WXUNUSED(n)) const
546 {
547 wxFAIL_MSG( wxT("wxChoice::DoGetItemClientObject not implemented") );
548 return (wxClientData*) NULL;
549 }
550
551 void wxChoice::Select(int n)
552 {
553 SetSelection(n);
554 }
555
556 void wxChoice::SetString(int WXUNUSED(n), const wxString& WXUNUSED(s))
557 {
558 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
559 }