More Motif changes (colour/font stuff)
[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 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/choice.h"
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"
26
27 #if !USE_SHARED_LIBRARY
28 IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
29 #endif
30
31 void wxChoiceCallback (Widget w, XtPointer clientData,
32 XtPointer ptr);
33
34 wxChoice::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;
41 }
42
43 bool 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;
55 m_buttonWidget = (WXWidget) 0;
56 m_menuWidget = (WXWidget) 0;
57 m_widgetList = (WXWidget*) 0;
58 m_formWidget = (WXWidget) 0;
59
60 if (parent) parent->AddChild(this);
61
62 if ( id == -1 )
63 m_windowId = (int)NewControlId();
64 else
65 m_windowId = id;
66
67 m_backgroundColour = parent->GetBackgroundColour();
68 m_foregroundColour = parent->GetForegroundColour();
69
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
125
126 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
127
128 AttachWidget (parent, m_buttonWidget, m_formWidget, pos.x, pos.y, size.x, size.y);
129
130 SetFont(* parent->GetFont());
131 ChangeBackgroundColour();
132
133 return TRUE;
134 }
135
136 wxChoice::~wxChoice()
137 {
138 // For some reason destroying the menuWidget
139 // can cause crashes on some machines. It will
140 // be deleted implicitly by deleting the parent form
141 // anyway.
142 // XtDestroyWidget (menuWidget);
143 if (m_widgetList)
144 delete[] m_widgetList;
145
146 DetachWidget(GetMainWidget()); // Removes event handlers
147
148 XtDestroyWidget((Widget) m_formWidget);
149 m_formWidget = (WXWidget) 0;
150
151 // Presumably the other widgets have been deleted now, via the form
152 m_mainWidget = (WXWidget) 0;
153 m_buttonWidget = (WXWidget) 0;
154 }
155
156 void wxChoice::Append(const wxString& item)
157 {
158 wxStripMenuCodes ((char *)(const char *)item, wxBuffer);
159 Widget w = XtVaCreateManagedWidget (wxBuffer,
160 #if USE_GADGETS
161 xmPushButtonGadgetClass, (Widget) m_menuWidget,
162 #else
163 xmPushButtonWidgetClass, (Widget) m_menuWidget,
164 #endif
165 NULL);
166
167 DoChangeBackgroundColour((WXWidget) w, m_backgroundColour);
168
169 if (m_windowFont.Ok())
170 XtVaSetValues (w,
171 XmNfontList, (XmFontList) m_windowFont.GetFontList(1.0, XtDisplay((Widget) m_formWidget)),
172 NULL);
173
174 WXWidget *new_widgetList = new WXWidget[m_noStrings + 1];
175 int i;
176 for (i = 0; i < m_noStrings; i++)
177 new_widgetList[i] = m_widgetList[i];
178 new_widgetList[m_noStrings] = (WXWidget) w;
179 if (m_widgetList)
180 delete[] m_widgetList;
181 m_widgetList = new_widgetList;
182
183 char mnem = wxFindMnemonic ((char*) (const char*) item);
184 if (mnem != 0)
185 XtVaSetValues (w, XmNmnemonic, mnem, NULL);
186
187 XtAddCallback (w, XmNactivateCallback, (XtCallbackProc) wxChoiceCallback, (XtPointer) this);
188
189 if (m_noStrings == 0 && m_buttonWidget)
190 {
191 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, w, NULL);
192 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
193 XmString text = XmStringCreateSimple ((char*) (const char*) item);
194 XtVaSetValues (label,
195 XmNlabelString, text,
196 NULL);
197 XmStringFree (text);
198 }
199 wxNode *node = m_stringList.Add (item);
200 XtVaSetValues (w, XmNuserData, node->Data (), NULL);
201
202 m_noStrings ++;
203 }
204
205 void wxChoice::Delete(int n)
206 {
207 wxFAIL_MSG( "Sorry, wxChoice::Delete isn't implemented yet. Maybe you'd like to volunteer? :-)" );
208
209 // What should we do -- remove the callback for this button widget,
210 // delete the m_stringList entry, delete the button widget, construct a new widget list
211 // (see Append)
212
213 // TODO
214 m_noStrings --;
215 }
216
217 void wxChoice::Clear()
218 {
219 m_stringList.Clear ();
220 int i;
221 for (i = 0; i < m_noStrings; i++)
222 {
223 XtUnmanageChild ((Widget) m_widgetList[i]);
224 XtDestroyWidget ((Widget) m_widgetList[i]);
225 }
226 if (m_noStrings)
227 delete[] m_widgetList;
228 m_widgetList = (WXWidget*) NULL;
229 if (m_buttonWidget)
230 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, (Widget) NULL, NULL);
231 m_noStrings = 0;
232 }
233
234 int wxChoice::GetSelection() const
235 {
236 XmString text;
237 char *s;
238 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
239 XtVaGetValues (label,
240 XmNlabelString, &text,
241 NULL);
242
243 if (XmStringGetLtoR (text, XmSTRING_DEFAULT_CHARSET, &s))
244 {
245 int i = 0;
246 for (wxNode * node = m_stringList.First (); node; node = node->Next ())
247 {
248 char *s1 = (char *) node->Data ();
249 if (s1 == s || strcmp (s1, s) == 0)
250 {
251 XmStringFree(text) ;
252 XtFree (s);
253 return i;
254 }
255 else
256 i++;
257 } // for()
258
259 XmStringFree(text) ;
260 XtFree (s);
261 return -1;
262 }
263 XmStringFree(text) ;
264 return -1;
265 }
266
267 void wxChoice::SetSelection(int n)
268 {
269 m_inSetValue = TRUE;
270
271 wxNode *node = m_stringList.Nth (n);
272 if (node)
273 {
274 Dimension selectionWidth, selectionHeight;
275
276 char *s = (char *) node->Data ();
277 XmString text = XmStringCreateSimple (s);
278 XtVaGetValues ((Widget) m_widgetList[n], XmNwidth, &selectionWidth, XmNheight, &selectionHeight, NULL);
279 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
280 XtVaSetValues (label,
281 XmNlabelString, text,
282 NULL);
283 XmStringFree (text);
284 XtVaSetValues ((Widget) m_buttonWidget,
285 XmNwidth, selectionWidth, XmNheight, selectionHeight,
286 XmNmenuHistory, (Widget) m_widgetList[n], NULL);
287 }
288 m_inSetValue = FALSE;
289 }
290
291 int wxChoice::FindString(const wxString& s) const
292 {
293 int i = 0;
294 for (wxNode * node = m_stringList.First (); node; node = node->Next ())
295 {
296 char *s1 = (char *) node->Data ();
297 if (s == s1)
298 {
299 return i;
300 }
301 else
302 i++;
303 }
304 return -1;
305 }
306
307 wxString wxChoice::GetString(int n) const
308 {
309 wxNode *node = m_stringList.Nth (n);
310 if (node)
311 return wxString((char *) node->Data ());
312 else
313 return wxEmptyString;
314 }
315
316 void wxChoice::SetColumns(int n)
317 {
318 if (n<1) n = 1 ;
319
320 short numColumns = n ;
321 Arg args[3];
322
323 XtSetArg(args[0], XmNnumColumns, numColumns);
324 XtSetArg(args[1], XmNpacking, XmPACK_COLUMN);
325 XtSetValues((Widget) m_menuWidget,args,2) ;
326 }
327
328 int wxChoice::GetColumns(void) const
329 {
330 short numColumns ;
331
332 XtVaGetValues((Widget) m_menuWidget,XmNnumColumns,&numColumns,NULL) ;
333 return numColumns ;
334 }
335
336 void wxChoice::SetFocus()
337 {
338 XmProcessTraversal(XtParent((Widget)m_mainWidget), XmTRAVERSE_CURRENT);
339 }
340
341 void wxChoice::SetSize(int x, int y, int width, int height, int sizeFlags)
342 {
343 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
344 bool managed = XtIsManaged((Widget) m_formWidget);
345
346 if (managed)
347 XtUnmanageChild ((Widget) m_formWidget);
348
349 int actualWidth = width, actualHeight = height;
350
351 if (width > -1)
352 {
353 int i;
354 for (i = 0; i < m_noStrings; i++)
355 XtVaSetValues ((Widget) m_widgetList[i], XmNwidth, actualWidth, NULL);
356 XtVaSetValues ((Widget) m_buttonWidget, XmNwidth, actualWidth,
357 NULL);
358 }
359 if (height > -1)
360 {
361 int i;
362 for (i = 0; i < m_noStrings; i++)
363 XtVaSetValues ((Widget) m_widgetList[i], XmNheight, actualHeight, NULL);
364 XtVaSetValues ((Widget) m_buttonWidget, XmNheight, actualHeight,
365 NULL);
366 }
367
368 if (managed)
369 XtManageChild ((Widget) m_formWidget);
370 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
371
372 wxControl::SetSize (x, y, width, height, sizeFlags);
373 }
374
375 wxString wxChoice::GetStringSelection () const
376 {
377 int sel = GetSelection ();
378 if (sel > -1)
379 return wxString(this->GetString (sel));
380 else
381 return wxEmptyString;
382 }
383
384 bool wxChoice::SetStringSelection (const wxString& s)
385 {
386 int sel = FindString (s);
387 if (sel > -1)
388 {
389 SetSelection (sel);
390 return TRUE;
391 }
392 else
393 return FALSE;
394 }
395
396 void wxChoice::Command(wxCommandEvent & event)
397 {
398 SetSelection (event.GetInt());
399 ProcessCommand (event);
400 }
401
402 void wxChoiceCallback (Widget w, XtPointer clientData,
403 XtPointer ptr)
404 {
405 wxChoice *item = (wxChoice *) clientData;
406 if (item)
407 {
408 if (item->InSetValue())
409 return;
410
411 char *s = NULL;
412 XtVaGetValues (w, XmNuserData, &s, NULL);
413 if (s)
414 {
415 wxCommandEvent event (wxEVT_COMMAND_CHOICE_SELECTED);
416 event.m_commandInt = item->FindString (s);
417 // event.m_commandString = s;
418 item->ProcessCommand (event);
419 }
420 }
421 }
422
423 void wxChoice::ChangeFont()
424 {
425 // Note that this causes the widget to be resized back
426 // to its original size! We therefore have to set the size
427 // back again. TODO: a better way in Motif?
428 if (m_windowFont.Ok())
429 {
430 int width, height, width1, height1;
431 GetSize(& width, & height);
432
433 XmFontList fontList = (XmFontList) m_windowFont.GetFontList(1.0, XtDisplay((Widget) m_mainWidget));
434 XtVaSetValues ((Widget) m_mainWidget, XmNfontList, fontList, NULL);
435 XtVaSetValues ((Widget) m_buttonWidget, XmNfontList, fontList, NULL);
436
437 int i;
438 for (i = 0; i < m_noStrings; i++)
439 XtVaSetValues ((Widget) m_widgetList[i], XmNfontList, fontList, NULL);
440 GetSize(& width1, & height1);
441 if (width != width1 || height != height1)
442 {
443 SetSize(-1, -1, width, height);
444 }
445 }
446 }
447
448 void wxChoice::ChangeBackgroundColour()
449 {
450 DoChangeBackgroundColour(m_formWidget, m_backgroundColour);
451 DoChangeBackgroundColour(m_buttonWidget, m_backgroundColour);
452 DoChangeBackgroundColour(m_menuWidget, m_backgroundColour);
453 int i;
454 for (i = 0; i < m_noStrings; i++)
455 DoChangeBackgroundColour(m_widgetList[i], m_backgroundColour);
456 }
457
458 void wxChoice::ChangeForegroundColour()
459 {
460 DoChangeForegroundColour(m_formWidget, m_foregroundColour);
461 DoChangeForegroundColour(m_buttonWidget, m_foregroundColour);
462 DoChangeForegroundColour(m_menuWidget, m_foregroundColour);
463 int i;
464 for (i = 0; i < m_noStrings; i++)
465 DoChangeForegroundColour(m_widgetList[i], m_foregroundColour);
466 }