Lots of wxMotif fixes
[wxWidgets.git] / src / motif / radiobox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: radiobox.cpp
3 // Purpose: wxRadioBox
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 "radiobox.h"
14 #endif
15
16 #include "wx/radiobox.h"
17 #include "wx/utils.h"
18
19 #include <Xm/Label.h>
20 #include <Xm/LabelG.h>
21 #include <Xm/ToggleB.h>
22 #include <Xm/ToggleBG.h>
23 #include <Xm/RowColumn.h>
24 #include <Xm/Form.h>
25
26 #include <wx/motif/private.h>
27
28 void wxRadioBoxCallback (Widget w, XtPointer clientData,
29 XmToggleButtonCallbackStruct * cbs);
30
31 #if !USE_SHARED_LIBRARY
32 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl)
33 #endif
34
35 // Radio box item
36 wxRadioBox::wxRadioBox()
37 {
38 m_selectedButton = -1;
39 m_noItems = 0;
40 m_noRowsOrCols = 0;
41 m_majorDim = 0 ;
42
43 m_formWidget = (WXWidget) 0;
44 m_labelWidget = (WXWidget) 0;
45 m_radioButtons = (WXWidget*) NULL;
46 m_radioButtonLabels = (wxString*) NULL;
47 }
48
49 bool wxRadioBox::Create(wxWindow *parent, wxWindowID id, const wxString& title,
50 const wxPoint& pos, const wxSize& size,
51 int n, const wxString choices[],
52 int majorDim, long style,
53 const wxValidator& val, const wxString& name)
54 {
55 m_selectedButton = -1;
56 m_noItems = n;
57 m_labelWidget = (WXWidget) 0;
58 m_radioButtons = (WXWidget*) NULL;
59 m_radioButtonLabels = (wxString*) NULL;
60 m_backgroundColour = parent->GetBackgroundColour();
61 m_foregroundColour = parent->GetForegroundColour();
62 m_windowFont = parent->GetFont();
63
64 SetName(name);
65 SetValidator(val);
66
67 parent->AddChild(this);
68
69 m_windowStyle = (long&)style;
70
71 if (id == -1)
72 m_windowId = NewControlId();
73 else
74 m_windowId = id;
75
76 m_noRowsOrCols = majorDim;
77
78 if (majorDim==0)
79 m_majorDim = n ;
80 else
81 m_majorDim = majorDim ;
82
83 Widget parentWidget = (Widget) parent->GetClientWidget();
84
85 wxString label1(wxStripMenuCodes(title));
86
87 XmString text = XmStringCreateSimple ((char*) (const char*) label1);
88
89 Widget formWidget = XtVaCreateManagedWidget ((char*) (const char*) name,
90 xmFormWidgetClass, parentWidget,
91 XmNmarginHeight, 0,
92 XmNmarginWidth, 0,
93 NULL);
94
95 m_formWidget = (WXWidget) formWidget;
96
97 XmFontList fontList = (XmFontList) m_windowFont.GetFontList(1.0, XtDisplay(parentWidget));
98 if (label1 != "")
99 {
100 text = XmStringCreateSimple ((char*) (const char*) label1);
101 Widget labelWidget = XtVaCreateManagedWidget ((char*) (const char*) label1,
102 #if wxUSE_GADGETS
103 style & wxCOLOURED ?
104 xmLabelWidgetClass : xmLabelGadgetClass,
105 formWidget,
106 #else
107 xmLabelWidgetClass, formWidget,
108 #endif
109 XmNfontList, fontList,
110 XmNlabelString, text,
111 NULL);
112
113 XmStringFree (text);
114 }
115
116 Arg args[3];
117
118 majorDim = (n + majorDim - 1) / majorDim;
119
120 XtSetArg (args[0], XmNorientation, ((style & wxHORIZONTAL) == wxHORIZONTAL ?
121 XmHORIZONTAL : XmVERTICAL));
122 XtSetArg (args[1], XmNnumColumns, majorDim);
123
124 Widget radioBoxWidget = XmCreateRadioBox (formWidget, "radioBoxWidget", args, 2);
125 m_mainWidget = (WXWidget) radioBoxWidget;
126
127
128 if (m_labelWidget)
129 XtVaSetValues ((Widget) m_labelWidget,
130 XmNtopAttachment, XmATTACH_FORM,
131 XmNleftAttachment, XmATTACH_FORM,
132 XmNalignment, XmALIGNMENT_BEGINNING,
133 NULL);
134
135 XtVaSetValues (radioBoxWidget,
136 XmNtopAttachment, m_labelWidget ? XmATTACH_WIDGET : XmATTACH_FORM,
137 XmNtopWidget, m_labelWidget ? (Widget) m_labelWidget : formWidget,
138 XmNbottomAttachment, XmATTACH_FORM,
139 XmNleftAttachment, XmATTACH_FORM,
140 NULL);
141
142 // if (style & wxFLAT)
143 // XtVaSetValues (radioBoxWidget, XmNborderWidth, 1, NULL);
144
145 m_radioButtons = new WXWidget[n];
146 m_radioButtonLabels = new wxString[n];
147 int i;
148 for (i = 0; i < n; i++)
149 {
150 wxString str(wxStripMenuCodes(choices[i]));
151 m_radioButtonLabels[i] = str;
152 m_radioButtons[i] = (WXWidget) XtVaCreateManagedWidget ((char*) (const char*) str,
153 #if wxUSE_GADGETS
154 xmToggleButtonGadgetClass, radioBoxWidget,
155 #else
156 xmToggleButtonWidgetClass, radioBoxWidget,
157 #endif
158 XmNfontList, fontList,
159 NULL);
160 XtAddCallback ((Widget) m_radioButtons[i], XmNvalueChangedCallback, (XtCallbackProc) wxRadioBoxCallback,
161 (XtCallbackProc) this);
162
163 }
164 SetSelection (0);
165
166 m_windowFont = parent->GetFont();
167 ChangeFont(FALSE);
168
169 XtManageChild (radioBoxWidget);
170
171 SetCanAddEventHandler(TRUE);
172 AttachWidget (parent, m_mainWidget, m_formWidget, pos.x, pos.y, size.x, size.y);
173
174 ChangeBackgroundColour();
175
176 return TRUE;
177 }
178
179
180 wxRadioBox::~wxRadioBox()
181 {
182 delete[] m_radioButtonLabels;
183 delete[] m_radioButtons;
184 DetachWidget(m_formWidget);
185 }
186
187 wxString wxRadioBox::GetLabel(int item) const
188 {
189 if (item < 0 || item >= m_noItems)
190 return wxEmptyString;
191
192 Widget widget = (Widget) m_radioButtons[item];
193 XmString text;
194 char *s;
195 XtVaGetValues (widget,
196 XmNlabelString, &text,
197 NULL);
198
199 if (XmStringGetLtoR (text, XmSTRING_DEFAULT_CHARSET, &s))
200 {
201 // Should we free 'text'???
202 XmStringFree(text);
203 wxString str(s);
204 XtFree (s);
205 return str;
206 }
207 else
208 {
209 XmStringFree(text);
210 return wxEmptyString;
211 }
212 }
213
214 void wxRadioBox::SetLabel(int item, const wxString& label)
215 {
216 if (item < 0 || item >= m_noItems)
217 return;
218
219 Widget widget = (Widget) m_radioButtons[item];
220 if (label != "")
221 {
222 wxString label1(wxStripMenuCodes(label));
223 XmString text = XmStringCreateSimple ((char*) (const char*) label1);
224 XtVaSetValues (widget,
225 XmNlabelString, text,
226 XmNlabelType, XmSTRING,
227 NULL);
228 XmStringFree (text);
229 }
230 }
231
232 int wxRadioBox::FindString(const wxString& s) const
233 {
234 int i;
235 for (i = 0; i < m_noItems; i++)
236 if (s == m_radioButtonLabels[i])
237 return i;
238 return -1;
239 }
240
241 void wxRadioBox::SetSelection(int n)
242 {
243 if ((n < 0) || (n >= m_noItems))
244 return;
245
246 m_selectedButton = n;
247
248 m_inSetValue = TRUE;
249
250 XmToggleButtonSetState ((Widget) m_radioButtons[n], TRUE, FALSE);
251
252 int i;
253 for (i = 0; i < m_noItems; i++)
254 if (i != n)
255 XmToggleButtonSetState ((Widget) m_radioButtons[i], FALSE, FALSE);
256
257 m_inSetValue = FALSE;
258 }
259
260 // Get single selection, for single choice list items
261 int wxRadioBox::GetSelection() const
262 {
263 return m_selectedButton;
264 }
265
266 // Find string for position
267 wxString wxRadioBox::GetString(int n) const
268 {
269 if ((n < 0) || (n >= m_noItems))
270 return wxEmptyString;
271 return m_radioButtonLabels[n];
272 }
273
274 void wxRadioBox::SetSize(int x, int y, int width, int height, int sizeFlags)
275 {
276 bool managed = XtIsManaged((Widget) m_formWidget);
277
278 if (managed)
279 XtUnmanageChild ((Widget) m_formWidget);
280
281 int xx = x; int yy = y;
282 AdjustForParentClientOrigin(xx, yy, sizeFlags);
283
284 if (x > -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
285 XtVaSetValues ((Widget) m_formWidget, XmNleftAttachment, XmATTACH_SELF,
286 XmNx, xx, NULL);
287 if (y > -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
288 XtVaSetValues ((Widget) m_formWidget, XmNtopAttachment, XmATTACH_SELF,
289 XmNy, yy, NULL);
290
291 // Must set the actual RadioBox to be desired size MINUS label size
292 Dimension labelWidth = 0, labelHeight = 0, actualWidth = 0, actualHeight = 0;
293
294 if (m_labelWidget)
295 XtVaGetValues ((Widget) m_labelWidget, XmNwidth, &labelWidth, XmNheight, &labelHeight, NULL);
296
297 actualWidth = width;
298 actualHeight = height - labelHeight;
299
300 if (width > -1)
301 {
302 XtVaSetValues ((Widget) m_mainWidget, XmNwidth, actualWidth, NULL);
303 }
304 if (height > -1)
305 {
306 XtVaSetValues ((Widget) m_mainWidget, XmNheight, actualHeight, NULL);
307 }
308 if (managed)
309 XtManageChild ((Widget) m_formWidget);
310 }
311
312 // Enable a specific button
313 void wxRadioBox::Enable(int n, bool enable)
314 {
315 if ((n < 0) || (n >= m_noItems))
316 return;
317
318 XtSetSensitive ((Widget) m_radioButtons[n], (Boolean) enable);
319 }
320
321 // Enable all controls
322 void wxRadioBox::Enable(bool enable)
323 {
324 wxControl::Enable(enable);
325
326 int i;
327 for (i = 0; i < m_noItems; i++)
328 XtSetSensitive ((Widget) m_radioButtons[i], (Boolean) enable);
329 }
330
331 // Show a specific button
332 void wxRadioBox::Show(int n, bool show)
333 {
334 // This method isn't complete, and we try do do our best...
335 // It's main purpose isn't for allowing Show/Unshow dynamically,
336 // but rather to provide a way to design wxRadioBox such:
337 //
338 // o Val1 o Val2 o Val3
339 // o Val4 o Val6
340 // o Val7 o Val8 o Val9
341 //
342 // In my case, this is a 'direction' box, and the Show(5,False) is
343 // coupled with an Enable(5,False)
344 //
345 if ((n < 0) || (n >= m_noItems))
346 return;
347
348 XtVaSetValues ((Widget) m_radioButtons[n],
349 XmNindicatorOn, (unsigned char) show,
350 NULL);
351
352 // Please note that this is all we can do: removing the label
353 // if switching to unshow state. However, when switching
354 // to the on state, it's the prog. resp. to call SetLabel(item,...)
355 // after this call!!
356 if (!show)
357 wxRadioBox::SetLabel (n, " ");
358 }
359
360 // For single selection items only
361 wxString wxRadioBox::GetStringSelection () const
362 {
363 int sel = GetSelection ();
364 if (sel > -1)
365 return this->GetString (sel);
366 else
367 return wxString("");
368 }
369
370 bool wxRadioBox::SetStringSelection (const wxString& s)
371 {
372 int sel = FindString (s);
373 if (sel > -1)
374 {
375 SetSelection (sel);
376 return TRUE;
377 }
378 else
379 return FALSE;
380 }
381
382 void wxRadioBox::Command (wxCommandEvent & event)
383 {
384 SetSelection (event.m_commandInt);
385 ProcessCommand (event);
386 }
387
388 void wxRadioBox::ChangeFont(bool keepOriginalSize)
389 {
390 wxWindow::ChangeFont(keepOriginalSize);
391
392 XmFontList fontList = (XmFontList) m_windowFont.GetFontList(1.0, XtDisplay((Widget) GetTopWidget()));
393
394 int i;
395 for (i = 0; i < m_noItems; i++)
396 {
397 WXWidget radioButton = m_radioButtons[i];
398
399 XtVaSetValues ((Widget) radioButton,
400 XmNfontList, fontList,
401 XmNtopAttachment, XmATTACH_FORM,
402 NULL);
403 }
404 }
405
406 void wxRadioBox::ChangeBackgroundColour()
407 {
408 wxWindow::ChangeBackgroundColour();
409
410 int i;
411 for (i = 0; i < m_noItems; i++)
412 {
413 WXWidget radioButton = m_radioButtons[i];
414
415 DoChangeBackgroundColour(radioButton, m_backgroundColour, TRUE);
416 }
417 }
418
419 void wxRadioBox::ChangeForegroundColour()
420 {
421 wxWindow::ChangeForegroundColour();
422
423 int i;
424 for (i = 0; i < m_noItems; i++)
425 {
426 WXWidget radioButton = m_radioButtons[i];
427
428 DoChangeForegroundColour(radioButton, m_foregroundColour);
429 }
430 }
431
432 void wxRadioBoxCallback (Widget w, XtPointer clientData,
433 XmToggleButtonCallbackStruct * cbs)
434 {
435 if (!cbs->set)
436 return;
437
438 wxRadioBox *item = (wxRadioBox *) clientData;
439 int sel = -1;
440 int i;
441 for (i = 0; i < item->Number(); i++)
442 if (item->GetRadioButtons() && ((Widget) (item->GetRadioButtons()[i]) == w))
443 sel = i;
444 item->SetSel(sel);
445
446 if (item->InSetValue())
447 return;
448
449 wxCommandEvent event (wxEVT_COMMAND_RADIOBOX_SELECTED, item->GetId());
450 event.m_commandInt = sel;
451 event.SetEventObject(item);
452 item->ProcessCommand (event);
453 }
454