wxChoice derives from wxChoiceBase; renamed Append to DoAppend
[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 int wxChoice::DoAppend(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 return Number() - 1;
231 }
232
233 void wxChoice::Delete(int WXUNUSED(n))
234 {
235 wxFAIL_MSG( "Sorry, wxChoice::Delete isn't implemented yet. Maybe you'd like to volunteer? :-)" );
236
237 // What should we do -- remove the callback for this button widget,
238 // delete the m_stringList entry, delete the button widget, construct a new widget list
239 // (see Append)
240
241 // TODO
242 m_noStrings --;
243 }
244
245 void wxChoice::Clear()
246 {
247 m_stringList.Clear ();
248 int i;
249 for (i = 0; i < m_noStrings; i++)
250 {
251 XtUnmanageChild ((Widget) m_widgetList[i]);
252 XtDestroyWidget ((Widget) m_widgetList[i]);
253 }
254 if (m_noStrings)
255 delete[] m_widgetList;
256 m_widgetList = (WXWidget*) NULL;
257 if (m_buttonWidget)
258 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, (Widget) NULL, NULL);
259
260 if ( HasClientObjectData() )
261 {
262 // destroy the data (due to Robert's idea of using wxList<wxObject>
263 // and not wxList<wxClientData> we can't just say
264 // m_clientList.DeleteContents(TRUE) - this would crash!
265 wxNode *node = m_clientList.First();
266 while ( node )
267 {
268 delete (wxClientData *)node->Data();
269 node = node->Next();
270 }
271 }
272 m_clientList.Clear();
273
274 m_noStrings = 0;
275 }
276
277 int wxChoice::GetSelection() const
278 {
279 XmString text;
280 char *s;
281 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
282 XtVaGetValues (label,
283 XmNlabelString, &text,
284 NULL);
285
286 if (XmStringGetLtoR (text, XmSTRING_DEFAULT_CHARSET, &s))
287 {
288 int i = 0;
289 for (wxNode * node = m_stringList.First (); node; node = node->Next ())
290 {
291 char *s1 = (char *) node->Data ();
292 if (s1 == s || strcmp (s1, s) == 0)
293 {
294 XmStringFree(text) ;
295 XtFree (s);
296 return i;
297 }
298 else
299 i++;
300 } // for()
301
302 XmStringFree(text) ;
303 XtFree (s);
304 return -1;
305 }
306 XmStringFree(text) ;
307 return -1;
308 }
309
310 void wxChoice::SetSelection(int n)
311 {
312 m_inSetValue = TRUE;
313
314 wxNode *node = m_stringList.Nth (n);
315 if (node)
316 {
317 Dimension selectionWidth, selectionHeight;
318
319 char *s = (char *) node->Data ();
320 XmString text = XmStringCreateSimple (s);
321 XtVaGetValues ((Widget) m_widgetList[n], XmNwidth, &selectionWidth, XmNheight, &selectionHeight, NULL);
322 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
323 XtVaSetValues (label,
324 XmNlabelString, text,
325 NULL);
326 XmStringFree (text);
327 XtVaSetValues ((Widget) m_buttonWidget,
328 XmNwidth, selectionWidth, XmNheight, selectionHeight,
329 XmNmenuHistory, (Widget) m_widgetList[n], NULL);
330 }
331 m_inSetValue = FALSE;
332 }
333
334 int wxChoice::FindString(const wxString& s) const
335 {
336 int i = 0;
337 for (wxNode * node = m_stringList.First (); node; node = node->Next ())
338 {
339 char *s1 = (char *) node->Data ();
340 if (s == s1)
341 {
342 return i;
343 }
344 else
345 i++;
346 }
347 return -1;
348 }
349
350 wxString wxChoice::GetString(int n) const
351 {
352 wxNode *node = m_stringList.Nth (n);
353 if (node)
354 return wxString((char *) node->Data ());
355 else
356 return wxEmptyString;
357 }
358
359 void wxChoice::SetColumns(int n)
360 {
361 if (n<1) n = 1 ;
362
363 short numColumns = n ;
364 Arg args[3];
365
366 XtSetArg(args[0], XmNnumColumns, numColumns);
367 XtSetArg(args[1], XmNpacking, XmPACK_COLUMN);
368 XtSetValues((Widget) m_menuWidget,args,2) ;
369 }
370
371 int wxChoice::GetColumns(void) const
372 {
373 short numColumns ;
374
375 XtVaGetValues((Widget) m_menuWidget,XmNnumColumns,&numColumns,NULL) ;
376 return numColumns ;
377 }
378
379 void wxChoice::SetFocus()
380 {
381 XmProcessTraversal(XtParent((Widget)m_mainWidget), XmTRAVERSE_CURRENT);
382 }
383
384 void wxChoice::DoSetSize(int x, int y, int width, int height, int sizeFlags)
385 {
386 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
387 bool managed = XtIsManaged((Widget) m_formWidget);
388
389 if (managed)
390 XtUnmanageChild ((Widget) m_formWidget);
391
392 int actualWidth = width, actualHeight = height;
393
394 if (width > -1)
395 {
396 int i;
397 for (i = 0; i < m_noStrings; i++)
398 XtVaSetValues ((Widget) m_widgetList[i], XmNwidth, actualWidth, NULL);
399 XtVaSetValues ((Widget) m_buttonWidget, XmNwidth, actualWidth,
400 NULL);
401 }
402 if (height > -1)
403 {
404 int i;
405 for (i = 0; i < m_noStrings; i++)
406 XtVaSetValues ((Widget) m_widgetList[i], XmNheight, actualHeight, NULL);
407 XtVaSetValues ((Widget) m_buttonWidget, XmNheight, actualHeight,
408 NULL);
409 }
410
411 if (managed)
412 XtManageChild ((Widget) m_formWidget);
413 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
414
415 wxControl::DoSetSize (x, y, width, height, sizeFlags);
416 }
417
418 wxString wxChoice::GetStringSelection () const
419 {
420 int sel = GetSelection ();
421 if (sel > -1)
422 return wxString(this->GetString (sel));
423 else
424 return wxEmptyString;
425 }
426
427 bool wxChoice::SetStringSelection (const wxString& s)
428 {
429 int sel = FindString (s);
430 if (sel > -1)
431 {
432 SetSelection (sel);
433 return TRUE;
434 }
435 else
436 return FALSE;
437 }
438
439 void wxChoice::Command(wxCommandEvent & event)
440 {
441 SetSelection (event.GetInt());
442 ProcessCommand (event);
443 }
444
445 void wxChoiceCallback (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
446 {
447 wxChoice *item = (wxChoice *) clientData;
448 if (item)
449 {
450 if (item->InSetValue())
451 return;
452
453 char *s = NULL;
454 XtVaGetValues (w, XmNuserData, &s, NULL);
455 if (s)
456 {
457 wxCommandEvent event (wxEVT_COMMAND_CHOICE_SELECTED, item->GetId());
458 event.SetEventObject(item);
459 event.m_commandInt = item->FindString (s);
460 // event.m_commandString = s;
461 item->ProcessCommand (event);
462 }
463 }
464 }
465
466 void wxChoice::ChangeFont(bool keepOriginalSize)
467 {
468 // Note that this causes the widget to be resized back
469 // to its original size! We therefore have to set the size
470 // back again. TODO: a better way in Motif?
471 if (m_font.Ok())
472 {
473 int width, height, width1, height1;
474 GetSize(& width, & height);
475
476 XmFontList fontList = (XmFontList) m_font.GetFontList(1.0, XtDisplay((Widget) m_mainWidget));
477 XtVaSetValues ((Widget) m_mainWidget, XmNfontList, fontList, NULL);
478 XtVaSetValues ((Widget) m_buttonWidget, XmNfontList, fontList, NULL);
479
480 /* TODO: why does this cause a crash in XtWidgetToApplicationContext?
481 int i;
482 for (i = 0; i < m_noStrings; i++)
483 XtVaSetValues ((Widget) m_widgetList[i], XmNfontList, fontList, NULL);
484 */
485 GetSize(& width1, & height1);
486 if (keepOriginalSize && (width != width1 || height != height1))
487 {
488 SetSize(-1, -1, width, height);
489 }
490 }
491 }
492
493 void wxChoice::ChangeBackgroundColour()
494 {
495 DoChangeBackgroundColour(m_formWidget, m_backgroundColour);
496 DoChangeBackgroundColour(m_buttonWidget, m_backgroundColour);
497 DoChangeBackgroundColour(m_menuWidget, m_backgroundColour);
498 int i;
499 for (i = 0; i < m_noStrings; i++)
500 DoChangeBackgroundColour(m_widgetList[i], m_backgroundColour);
501 }
502
503 void wxChoice::ChangeForegroundColour()
504 {
505 DoChangeForegroundColour(m_formWidget, m_foregroundColour);
506 DoChangeForegroundColour(m_buttonWidget, m_foregroundColour);
507 DoChangeForegroundColour(m_menuWidget, m_foregroundColour);
508 int i;
509 for (i = 0; i < m_noStrings; i++)
510 DoChangeForegroundColour(m_widgetList[i], m_foregroundColour);
511 }
512
513
514 // These implement functions needed by wxControlWithItems.
515 // Unfortunately, they're not all implemented yet.
516
517 int wxChoice::GetCount() const
518 {
519 return Number();
520 }
521
522 /*
523 int wxChoice::DoAppend(const wxString& item)
524 {
525 Append(item);
526 return GetCount() - 1;
527 }
528 */
529
530 // Just appends, doesn't yet insert
531 void wxChoice::DoInsertItems(const wxArrayString& items, int WXUNUSED(pos))
532 {
533 size_t nItems = items.GetCount();
534
535 for ( size_t n = 0; n < nItems; n++ )
536 {
537 Append( items[n]);
538 }
539 }
540
541 void wxChoice::DoSetItems(const wxArrayString& items, void **WXUNUSED(clientData))
542 {
543 Clear();
544 size_t nItems = items.GetCount();
545
546 for ( size_t n = 0; n < nItems; n++ )
547 {
548 Append(items[n]);
549 }
550 }
551
552 void wxChoice::DoSetFirstItem(int WXUNUSED(n))
553 {
554 wxFAIL_MSG( wxT("wxChoice::DoSetFirstItem not implemented") );
555 }
556
557 void wxChoice::DoSetItemClientData(int n, void* clientData)
558 {
559 wxNode *node = m_clientList.Nth( n );
560 wxCHECK_RET( node, wxT("invalid index in wxChoice::DoSetItemClientData") );
561
562 node->SetData( (wxObject*) clientData );
563 }
564
565 void* wxChoice::DoGetItemClientData(int n) const
566 {
567 wxNode *node = m_clientList.Nth( n );
568 wxCHECK_MSG( node, NULL, wxT("invalid index in wxChoice::DoGetItemClientData") );
569
570 return node->Data();
571 }
572
573 void wxChoice::DoSetItemClientObject(int n, wxClientData* clientData)
574 {
575 wxNode *node = m_clientList.Nth( n );
576 wxCHECK_RET( node, wxT("invalid index in wxChoice::DoSetItemClientObject") );
577
578 wxClientData *cd = (wxClientData*) node->Data();
579 delete cd;
580
581 node->SetData( (wxObject*) clientData );
582 }
583
584 wxClientData* wxChoice::DoGetItemClientObject(int n) const
585 {
586 wxNode *node = m_clientList.Nth( n );
587 wxCHECK_MSG( node, (wxClientData *)NULL,
588 wxT("invalid index in wxChoice::DoGetItemClientObject") );
589
590 return (wxClientData*) node->Data();
591 }
592
593 void wxChoice::Select(int n)
594 {
595 SetSelection(n);
596 }
597
598 void wxChoice::SetString(int WXUNUSED(n), const wxString& WXUNUSED(s))
599 {
600 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
601 }