]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/motif/choice.cpp
Michael Fieldings patch 598106 applied in part
[wxWidgets.git] / src / motif / choice.cpp
... / ...
CommitLineData
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
39IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
40
41void wxChoiceCallback (Widget w, XtPointer clientData,
42 XtPointer ptr);
43
44wxChoice::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
53bool 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
151wxChoice::~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
175int 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
233void 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
245void 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
277int 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
310void 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
334int 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
350wxString 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
359void 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
371int wxChoice::GetColumns(void) const
372{
373 short numColumns ;
374
375 XtVaGetValues((Widget) m_menuWidget,XmNnumColumns,&numColumns,NULL) ;
376 return numColumns ;
377}
378
379void wxChoice::SetFocus()
380{
381 XmProcessTraversal(XtParent((Widget)m_mainWidget), XmTRAVERSE_CURRENT);
382}
383
384void 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
418wxString 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
427bool 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
439void wxChoice::Command(wxCommandEvent & event)
440{
441 SetSelection (event.GetInt());
442 ProcessCommand (event);
443}
444
445void 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
466void 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
493void 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
503void 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
517int wxChoice::GetCount() const
518{
519 return Number();
520}
521
522/*
523int wxChoice::DoAppend(const wxString& item)
524{
525 Append(item);
526 return GetCount() - 1;
527}
528*/
529
530// Just appends, doesn't yet insert
531void 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
541void 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
552void wxChoice::DoSetFirstItem(int WXUNUSED(n))
553{
554 wxFAIL_MSG( wxT("wxChoice::DoSetFirstItem not implemented") );
555}
556
557void 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
565void* 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
573void 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
584wxClientData* 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
593void wxChoice::Select(int n)
594{
595 SetSelection(n);
596}
597
598void wxChoice::SetString(int WXUNUSED(n), const wxString& WXUNUSED(s))
599{
600 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
601}