1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "choice.h"
17 #define XtDisplay XTDISPLAY
18 #define XtParent XTPARENT
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/choice.h"
26 #pragma message disable nosimpint
29 #include <Xm/PushBG.h>
31 #include <Xm/RowColumn.h>
33 #pragma message enable nosimpint
36 #include "wx/motif/private.h"
38 IMPLEMENT_DYNAMIC_CLASS(wxChoice
, wxControl
)
40 void wxChoiceCallback (Widget w
, XtPointer clientData
,
46 m_buttonWidget
= (WXWidget
) 0;
47 m_menuWidget
= (WXWidget
) 0;
48 m_widgetList
= (WXWidget
*) 0;
49 m_formWidget
= (WXWidget
) 0;
52 bool wxChoice::Create(wxWindow
*parent
, wxWindowID id
,
55 int n
, const wxString choices
[],
57 const wxValidator
& validator
,
61 SetValidator(validator
);
62 m_noStrings
= 0; // Starts off with none, incremented in Append
63 m_windowStyle
= style
;
64 m_buttonWidget
= (WXWidget
) 0;
65 m_menuWidget
= (WXWidget
) 0;
66 m_widgetList
= (WXWidget
*) 0;
67 m_formWidget
= (WXWidget
) 0;
69 if (parent
) parent
->AddChild(this);
72 m_windowId
= (int)NewControlId();
76 m_backgroundColour
= parent
->GetBackgroundColour();
77 m_foregroundColour
= parent
->GetForegroundColour();
78 m_font
= parent
->GetFont();
80 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
82 m_formWidget
= (WXWidget
) XtVaCreateManagedWidget(name
.c_str(),
83 xmRowColumnWidgetClass
, parentWidget
,
86 XmNpacking
, XmPACK_TIGHT
,
87 XmNorientation
, XmHORIZONTAL
,
90 XtVaSetValues ((Widget
) m_formWidget
, XmNspacing
, 0, NULL
);
93 * Create the popup menu
95 m_menuWidget
= (WXWidget
) XmCreatePulldownMenu ((Widget
) m_formWidget
, "choiceMenu", NULL
, 0);
101 for (i
= 0; i
< n
; i
++)
111 XtSetArg (args
[argcnt
], XmNsubMenuId
, (Widget
) m_menuWidget
);
113 XtSetArg (args
[argcnt
], XmNmarginWidth
, 0);
115 XtSetArg (args
[argcnt
], XmNmarginHeight
, 0);
117 XtSetArg (args
[argcnt
], XmNpacking
, XmPACK_TIGHT
);
119 m_buttonWidget
= (WXWidget
) XmCreateOptionMenu ((Widget
) m_formWidget
, "choiceButton", args
, argcnt
);
121 m_mainWidget
= m_buttonWidget
;
123 XtManageChild ((Widget
) m_buttonWidget
);
125 // New code from Roland Haenel (roland_haenel@ac.cybercity.de)
126 // Some time ago, I reported a problem with wxChoice-items under
127 // Linux and Motif 2.0 (they caused sporadic GPFs). Now it seems
128 // that I have found the code responsible for this behaviour.
129 #if XmVersion >= 1002
131 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
132 // in controls sample.
134 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
135 // XtUnmanageChild (optionLabel);
139 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
143 AttachWidget (parent
, m_buttonWidget
, m_formWidget
, pos
.x
, pos
.y
, size
.x
, size
.y
);
145 ChangeBackgroundColour();
150 wxChoice::~wxChoice()
152 // For some reason destroying the menuWidget
153 // can cause crashes on some machines. It will
154 // be deleted implicitly by deleting the parent form
156 // XtDestroyWidget (menuWidget);
158 delete[] m_widgetList
;
162 DetachWidget(GetMainWidget()); // Removes event handlers
163 DetachWidget(m_formWidget
);
165 XtDestroyWidget((Widget
) m_formWidget
);
166 m_formWidget
= (WXWidget
) 0;
168 // Presumably the other widgets have been deleted now, via the form
169 m_mainWidget
= (WXWidget
) 0;
170 m_buttonWidget
= (WXWidget
) 0;
174 void wxChoice::Append(const wxString
& item
)
176 Widget w
= XtVaCreateManagedWidget (wxStripMenuCodes(item
),
178 xmPushButtonGadgetClass
, (Widget
) m_menuWidget
,
180 xmPushButtonWidgetClass
, (Widget
) m_menuWidget
,
184 DoChangeBackgroundColour((WXWidget
) w
, m_backgroundColour
);
188 XmNfontList
, (XmFontList
) m_font
.GetFontList(1.0, XtDisplay((Widget
) m_formWidget
)),
191 WXWidget
*new_widgetList
= new WXWidget
[m_noStrings
+ 1];
194 for (i
= 0; i
< m_noStrings
; i
++)
195 new_widgetList
[i
] = m_widgetList
[i
];
197 new_widgetList
[m_noStrings
] = (WXWidget
) w
;
200 delete[] m_widgetList
;
201 m_widgetList
= new_widgetList
;
203 char mnem
= wxFindMnemonic ((char*) (const char*) item
);
205 XtVaSetValues (w
, XmNmnemonic
, mnem
, NULL
);
207 XtAddCallback (w
, XmNactivateCallback
, (XtCallbackProc
) wxChoiceCallback
, (XtPointer
) this);
209 if (m_noStrings
== 0 && m_buttonWidget
)
211 XtVaSetValues ((Widget
) m_buttonWidget
, XmNmenuHistory
, w
, NULL
);
212 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
213 XmString text
= XmStringCreateSimple ((char*) (const char*) item
);
214 XtVaSetValues (label
,
215 XmNlabelString
, text
,
219 wxNode
*node
= m_stringList
.Add (item
);
220 XtVaSetValues (w
, XmNuserData
, node
->Data (), NULL
);
222 if (m_noStrings
== 0)
223 m_clientList
.Append((wxObject
*) NULL
);
225 m_clientList
.Insert( m_clientList
.Item(m_noStrings
-1),
230 void wxChoice::Delete(int WXUNUSED(n
))
232 wxFAIL_MSG( "Sorry, wxChoice::Delete isn't implemented yet. Maybe you'd like to volunteer? :-)" );
234 // What should we do -- remove the callback for this button widget,
235 // delete the m_stringList entry, delete the button widget, construct a new widget list
242 void wxChoice::Clear()
244 m_stringList
.Clear ();
246 for (i
= 0; i
< m_noStrings
; i
++)
248 XtUnmanageChild ((Widget
) m_widgetList
[i
]);
249 XtDestroyWidget ((Widget
) m_widgetList
[i
]);
252 delete[] m_widgetList
;
253 m_widgetList
= (WXWidget
*) NULL
;
255 XtVaSetValues ((Widget
) m_buttonWidget
, XmNmenuHistory
, (Widget
) NULL
, NULL
);
257 if ( HasClientObjectData() )
259 // destroy the data (due to Robert's idea of using wxList<wxObject>
260 // and not wxList<wxClientData> we can't just say
261 // m_clientList.DeleteContents(TRUE) - this would crash!
262 wxNode
*node
= m_clientList
.First();
265 delete (wxClientData
*)node
->Data();
269 m_clientList
.Clear();
274 int wxChoice::GetSelection() const
278 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
279 XtVaGetValues (label
,
280 XmNlabelString
, &text
,
283 if (XmStringGetLtoR (text
, XmSTRING_DEFAULT_CHARSET
, &s
))
286 for (wxNode
* node
= m_stringList
.First (); node
; node
= node
->Next ())
288 char *s1
= (char *) node
->Data ();
289 if (s1
== s
|| strcmp (s1
, s
) == 0)
307 void wxChoice::SetSelection(int n
)
311 wxNode
*node
= m_stringList
.Nth (n
);
314 Dimension selectionWidth
, selectionHeight
;
316 char *s
= (char *) node
->Data ();
317 XmString text
= XmStringCreateSimple (s
);
318 XtVaGetValues ((Widget
) m_widgetList
[n
], XmNwidth
, &selectionWidth
, XmNheight
, &selectionHeight
, NULL
);
319 Widget label
= XmOptionButtonGadget ((Widget
) m_buttonWidget
);
320 XtVaSetValues (label
,
321 XmNlabelString
, text
,
324 XtVaSetValues ((Widget
) m_buttonWidget
,
325 XmNwidth
, selectionWidth
, XmNheight
, selectionHeight
,
326 XmNmenuHistory
, (Widget
) m_widgetList
[n
], NULL
);
328 m_inSetValue
= FALSE
;
331 int wxChoice::FindString(const wxString
& s
) const
334 for (wxNode
* node
= m_stringList
.First (); node
; node
= node
->Next ())
336 char *s1
= (char *) node
->Data ();
347 wxString
wxChoice::GetString(int n
) const
349 wxNode
*node
= m_stringList
.Nth (n
);
351 return wxString((char *) node
->Data ());
353 return wxEmptyString
;
356 void wxChoice::SetColumns(int n
)
360 short numColumns
= n
;
363 XtSetArg(args
[0], XmNnumColumns
, numColumns
);
364 XtSetArg(args
[1], XmNpacking
, XmPACK_COLUMN
);
365 XtSetValues((Widget
) m_menuWidget
,args
,2) ;
368 int wxChoice::GetColumns(void) const
372 XtVaGetValues((Widget
) m_menuWidget
,XmNnumColumns
,&numColumns
,NULL
) ;
376 void wxChoice::SetFocus()
378 XmProcessTraversal(XtParent((Widget
)m_mainWidget
), XmTRAVERSE_CURRENT
);
381 void wxChoice::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
383 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_ANY
, NULL
);
384 bool managed
= XtIsManaged((Widget
) m_formWidget
);
387 XtUnmanageChild ((Widget
) m_formWidget
);
389 int actualWidth
= width
, actualHeight
= height
;
394 for (i
= 0; i
< m_noStrings
; i
++)
395 XtVaSetValues ((Widget
) m_widgetList
[i
], XmNwidth
, actualWidth
, NULL
);
396 XtVaSetValues ((Widget
) m_buttonWidget
, XmNwidth
, actualWidth
,
402 for (i
= 0; i
< m_noStrings
; i
++)
403 XtVaSetValues ((Widget
) m_widgetList
[i
], XmNheight
, actualHeight
, NULL
);
404 XtVaSetValues ((Widget
) m_buttonWidget
, XmNheight
, actualHeight
,
409 XtManageChild ((Widget
) m_formWidget
);
410 XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
412 wxControl::DoSetSize (x
, y
, width
, height
, sizeFlags
);
415 wxString
wxChoice::GetStringSelection () const
417 int sel
= GetSelection ();
419 return wxString(this->GetString (sel
));
421 return wxEmptyString
;
424 bool wxChoice::SetStringSelection (const wxString
& s
)
426 int sel
= FindString (s
);
436 void wxChoice::Command(wxCommandEvent
& event
)
438 SetSelection (event
.GetInt());
439 ProcessCommand (event
);
442 void wxChoiceCallback (Widget w
, XtPointer clientData
, XtPointer
WXUNUSED(ptr
))
444 wxChoice
*item
= (wxChoice
*) clientData
;
447 if (item
->InSetValue())
451 XtVaGetValues (w
, XmNuserData
, &s
, NULL
);
454 wxCommandEvent
event (wxEVT_COMMAND_CHOICE_SELECTED
, item
->GetId());
455 event
.SetEventObject(item
);
456 event
.m_commandInt
= item
->FindString (s
);
457 // event.m_commandString = s;
458 item
->ProcessCommand (event
);
463 void wxChoice::ChangeFont(bool keepOriginalSize
)
465 // Note that this causes the widget to be resized back
466 // to its original size! We therefore have to set the size
467 // back again. TODO: a better way in Motif?
470 int width
, height
, width1
, height1
;
471 GetSize(& width
, & height
);
473 XmFontList fontList
= (XmFontList
) m_font
.GetFontList(1.0, XtDisplay((Widget
) m_mainWidget
));
474 XtVaSetValues ((Widget
) m_mainWidget
, XmNfontList
, fontList
, NULL
);
475 XtVaSetValues ((Widget
) m_buttonWidget
, XmNfontList
, fontList
, NULL
);
477 /* TODO: why does this cause a crash in XtWidgetToApplicationContext?
479 for (i = 0; i < m_noStrings; i++)
480 XtVaSetValues ((Widget) m_widgetList[i], XmNfontList, fontList, NULL);
482 GetSize(& width1
, & height1
);
483 if (keepOriginalSize
&& (width
!= width1
|| height
!= height1
))
485 SetSize(-1, -1, width
, height
);
490 void wxChoice::ChangeBackgroundColour()
492 DoChangeBackgroundColour(m_formWidget
, m_backgroundColour
);
493 DoChangeBackgroundColour(m_buttonWidget
, m_backgroundColour
);
494 DoChangeBackgroundColour(m_menuWidget
, m_backgroundColour
);
496 for (i
= 0; i
< m_noStrings
; i
++)
497 DoChangeBackgroundColour(m_widgetList
[i
], m_backgroundColour
);
500 void wxChoice::ChangeForegroundColour()
502 DoChangeForegroundColour(m_formWidget
, m_foregroundColour
);
503 DoChangeForegroundColour(m_buttonWidget
, m_foregroundColour
);
504 DoChangeForegroundColour(m_menuWidget
, m_foregroundColour
);
506 for (i
= 0; i
< m_noStrings
; i
++)
507 DoChangeForegroundColour(m_widgetList
[i
], m_foregroundColour
);
511 // These implement functions needed by wxControlWithItems.
512 // Unfortunately, they're not all implemented yet.
514 int wxChoice::GetCount() const
519 int wxChoice::DoAppend(const wxString
& item
)
522 return GetCount() - 1;
525 // Just appends, doesn't yet insert
526 void wxChoice::DoInsertItems(const wxArrayString
& items
, int WXUNUSED(pos
))
528 size_t nItems
= items
.GetCount();
530 for ( size_t n
= 0; n
< nItems
; n
++ )
536 void wxChoice::DoSetItems(const wxArrayString
& items
, void **WXUNUSED(clientData
))
539 size_t nItems
= items
.GetCount();
541 for ( size_t n
= 0; n
< nItems
; n
++ )
547 void wxChoice::DoSetFirstItem(int WXUNUSED(n
))
549 wxFAIL_MSG( wxT("wxChoice::DoSetFirstItem not implemented") );
552 void wxChoice::DoSetItemClientData(int n
, void* clientData
)
554 wxNode
*node
= m_clientList
.Nth( n
);
555 wxCHECK_RET( node
, wxT("invalid index in wxChoice::DoSetItemClientData") );
557 node
->SetData( (wxObject
*) clientData
);
560 void* wxChoice::DoGetItemClientData(int n
) const
562 wxNode
*node
= m_clientList
.Nth( n
);
563 wxCHECK_MSG( node
, NULL
, wxT("invalid index in wxChoice::DoGetItemClientData") );
568 void wxChoice::DoSetItemClientObject(int n
, wxClientData
* clientData
)
570 wxNode
*node
= m_clientList
.Nth( n
);
571 wxCHECK_RET( node
, wxT("invalid index in wxChoice::DoSetItemClientObject") );
573 wxClientData
*cd
= (wxClientData
*) node
->Data();
576 node
->SetData( (wxObject
*) clientData
);
579 wxClientData
* wxChoice::DoGetItemClientObject(int n
) const
581 wxNode
*node
= m_clientList
.Nth( n
);
582 wxCHECK_MSG( node
, (wxClientData
*)NULL
,
583 wxT("invalid index in wxChoice::DoGetItemClientObject") );
585 return (wxClientData
*) node
->Data();
588 void wxChoice::Select(int n
)
593 void wxChoice::SetString(int WXUNUSED(n
), const wxString
& WXUNUSED(s
))
595 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );