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