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