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