]> git.saurik.com Git - wxWidgets.git/blame - src/motif/choice.cpp
Minor compilation fixes for Borland.
[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
338dd992
JJ
20#ifdef __VMS__
21#pragma message disable nosimpint
22#endif
f97c9854
JS
23#include <Xm/Xm.h>
24#include <Xm/PushBG.h>
25#include <Xm/PushB.h>
26#include <Xm/RowColumn.h>
338dd992
JJ
27#ifdef __VMS__
28#pragma message enable nosimpint
29#endif
f97c9854
JS
30
31#include "wx/motif/private.h"
4bb6408c 32
4bb6408c 33IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
4bb6408c 34
f97c9854 35void wxChoiceCallback (Widget w, XtPointer clientData,
2d120f83 36 XtPointer ptr);
f97c9854
JS
37
38wxChoice::wxChoice()
39{
40 m_noStrings = 0;
41 m_buttonWidget = (WXWidget) 0;
42 m_menuWidget = (WXWidget) 0;
43 m_widgetList = (WXWidget*) 0;
44 m_formWidget = (WXWidget) 0;
f97c9854
JS
45}
46
4bb6408c 47bool wxChoice::Create(wxWindow *parent, wxWindowID id,
2d120f83
JS
48 const wxPoint& pos,
49 const wxSize& size,
50 int n, const wxString choices[],
51 long style,
52 const wxValidator& validator,
53 const wxString& name)
4bb6408c
JS
54{
55 SetName(name);
56 SetValidator(validator);
ea57084d 57 m_noStrings = 0; // Starts off with none, incremented in Append
4bb6408c 58 m_windowStyle = style;
f97c9854
JS
59 m_buttonWidget = (WXWidget) 0;
60 m_menuWidget = (WXWidget) 0;
61 m_widgetList = (WXWidget*) 0;
62 m_formWidget = (WXWidget) 0;
31528cd3 63
4bb6408c 64 if (parent) parent->AddChild(this);
31528cd3 65
4bb6408c 66 if ( id == -1 )
2d120f83 67 m_windowId = (int)NewControlId();
4bb6408c 68 else
2d120f83 69 m_windowId = id;
31528cd3 70
0d57be45
JS
71 m_backgroundColour = parent->GetBackgroundColour();
72 m_foregroundColour = parent->GetForegroundColour();
da175b2c 73 m_font = parent->GetFont();
31528cd3 74
f97c9854 75 Widget parentWidget = (Widget) parent->GetClientWidget();
31528cd3
VZ
76
77 m_formWidget = (WXWidget) XtVaCreateManagedWidget(name.c_str(),
2d120f83
JS
78 xmRowColumnWidgetClass, parentWidget,
79 XmNmarginHeight, 0,
80 XmNmarginWidth, 0,
81 XmNpacking, XmPACK_TIGHT,
82 XmNorientation, XmHORIZONTAL,
83 NULL);
31528cd3 84
f97c9854 85 XtVaSetValues ((Widget) m_formWidget, XmNspacing, 0, NULL);
31528cd3 86
2d120f83 87 /*
f97c9854
JS
88 * Create the popup menu
89 */
90 m_menuWidget = (WXWidget) XmCreatePulldownMenu ((Widget) m_formWidget, "choiceMenu", NULL, 0);
31528cd3 91
2d120f83 92 // int i;
f97c9854
JS
93 if (n > 0)
94 {
95 int i;
96 for (i = 0; i < n; i++)
97 Append (choices[i]);
98 }
31528cd3 99
2d120f83 100 /*
f97c9854
JS
101 * Create button
102 */
103 Arg args[10];
104 Cardinal argcnt = 0;
31528cd3 105
f97c9854
JS
106 XtSetArg (args[argcnt], XmNsubMenuId, (Widget) m_menuWidget);
107 argcnt++;
108 XtSetArg (args[argcnt], XmNmarginWidth, 0);
109 argcnt++;
110 XtSetArg (args[argcnt], XmNmarginHeight, 0);
111 argcnt++;
112 XtSetArg (args[argcnt], XmNpacking, XmPACK_TIGHT);
113 argcnt++;
114 m_buttonWidget = (WXWidget) XmCreateOptionMenu ((Widget) m_formWidget, "choiceButton", args, argcnt);
31528cd3 115
f97c9854 116 m_mainWidget = m_buttonWidget;
31528cd3 117
f97c9854 118 XtManageChild ((Widget) m_buttonWidget);
9838df2c 119
f97c9854
JS
120 // New code from Roland Haenel (roland_haenel@ac.cybercity.de)
121 // Some time ago, I reported a problem with wxChoice-items under
122 // Linux and Motif 2.0 (they caused sporadic GPFs). Now it seems
123 // that I have found the code responsible for this behaviour.
124#if XmVersion >= 1002
125#if XmVersion < 2000
9838df2c
JS
126 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
127 // in controls sample.
dfe1eee3
VZ
128 //
129 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
130 // XtUnmanageChild (optionLabel);
f97c9854
JS
131#endif
132#endif
9838df2c 133
f97c9854 134 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
31528cd3 135
4b5f3fe6 136 ChangeFont(FALSE);
9838df2c 137
f97c9854 138 AttachWidget (parent, m_buttonWidget, m_formWidget, pos.x, pos.y, size.x, size.y);
31528cd3 139
0d57be45 140 ChangeBackgroundColour();
31528cd3 141
f97c9854
JS
142 return TRUE;
143}
144
145wxChoice::~wxChoice()
146{
2d120f83
JS
147 // For some reason destroying the menuWidget
148 // can cause crashes on some machines. It will
149 // be deleted implicitly by deleting the parent form
150 // anyway.
151 // XtDestroyWidget (menuWidget);
f97c9854
JS
152 if (m_widgetList)
153 delete[] m_widgetList;
31528cd3 154
8aa04e8b
JS
155 if (GetMainWidget())
156 {
157 DetachWidget(GetMainWidget()); // Removes event handlers
b412f9be 158 DetachWidget(m_formWidget);
31528cd3 159
8aa04e8b
JS
160 XtDestroyWidget((Widget) m_formWidget);
161 m_formWidget = (WXWidget) 0;
31528cd3 162
8aa04e8b
JS
163 // Presumably the other widgets have been deleted now, via the form
164 m_mainWidget = (WXWidget) 0;
165 m_buttonWidget = (WXWidget) 0;
166 }
4bb6408c
JS
167}
168
169void wxChoice::Append(const wxString& item)
170{
31528cd3 171 Widget w = XtVaCreateManagedWidget (wxStripMenuCodes(item),
f97c9854 172#if USE_GADGETS
2d120f83 173 xmPushButtonGadgetClass, (Widget) m_menuWidget,
f97c9854 174#else
2d120f83 175 xmPushButtonWidgetClass, (Widget) m_menuWidget,
f97c9854 176#endif
2d120f83 177 NULL);
31528cd3 178
2d120f83 179 DoChangeBackgroundColour((WXWidget) w, m_backgroundColour);
31528cd3 180
da175b2c 181 if (m_font.Ok())
2d120f83 182 XtVaSetValues (w,
da175b2c 183 XmNfontList, (XmFontList) m_font.GetFontList(1.0, XtDisplay((Widget) m_formWidget)),
2d120f83 184 NULL);
31528cd3 185
2d120f83
JS
186 WXWidget *new_widgetList = new WXWidget[m_noStrings + 1];
187 int i;
188 if (m_widgetList)
189 for (i = 0; i < m_noStrings; i++)
190 new_widgetList[i] = m_widgetList[i];
31528cd3 191
f6bcfd97 192 new_widgetList[m_noStrings] = (WXWidget) w;
31528cd3 193
f6bcfd97
BP
194 if (m_widgetList)
195 delete[] m_widgetList;
196 m_widgetList = new_widgetList;
31528cd3 197
f6bcfd97
BP
198 char mnem = wxFindMnemonic ((char*) (const char*) item);
199 if (mnem != 0)
200 XtVaSetValues (w, XmNmnemonic, mnem, NULL);
31528cd3 201
f6bcfd97 202 XtAddCallback (w, XmNactivateCallback, (XtCallbackProc) wxChoiceCallback, (XtPointer) this);
31528cd3 203
f6bcfd97
BP
204 if (m_noStrings == 0 && m_buttonWidget)
205 {
206 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, w, NULL);
207 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
208 XmString text = XmStringCreateSimple ((char*) (const char*) item);
209 XtVaSetValues (label,
210 XmNlabelString, text,
211 NULL);
212 XmStringFree (text);
213 }
214 wxNode *node = m_stringList.Add (item);
215 XtVaSetValues (w, XmNuserData, node->Data (), NULL);
31528cd3 216
f6bcfd97
BP
217 if (m_noStrings == 0)
218 m_clientList.Append((wxObject*) NULL);
219 else
220 m_clientList.Insert( m_clientList.Item(m_noStrings-1),
221 (wxObject*) NULL );
222 m_noStrings ++;
4bb6408c
JS
223}
224
f9e02ac7 225void wxChoice::Delete(int WXUNUSED(n))
4bb6408c 226{
f97c9854 227 wxFAIL_MSG( "Sorry, wxChoice::Delete isn't implemented yet. Maybe you'd like to volunteer? :-)" );
31528cd3 228
f97c9854
JS
229 // What should we do -- remove the callback for this button widget,
230 // delete the m_stringList entry, delete the button widget, construct a new widget list
231 // (see Append)
31528cd3 232
4bb6408c
JS
233 // TODO
234 m_noStrings --;
235}
236
237void wxChoice::Clear()
238{
f97c9854
JS
239 m_stringList.Clear ();
240 int i;
241 for (i = 0; i < m_noStrings; i++)
242 {
243 XtUnmanageChild ((Widget) m_widgetList[i]);
244 XtDestroyWidget ((Widget) m_widgetList[i]);
245 }
246 if (m_noStrings)
247 delete[] m_widgetList;
248 m_widgetList = (WXWidget*) NULL;
249 if (m_buttonWidget)
250 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, (Widget) NULL, NULL);
f6bcfd97
BP
251
252 if ( HasClientObjectData() )
253 {
254 // destroy the data (due to Robert's idea of using wxList<wxObject>
255 // and not wxList<wxClientData> we can't just say
256 // m_clientList.DeleteContents(TRUE) - this would crash!
257 wxNode *node = m_clientList.First();
258 while ( node )
259 {
260 delete (wxClientData *)node->Data();
261 node = node->Next();
262 }
263 }
264 m_clientList.Clear();
265
4bb6408c
JS
266 m_noStrings = 0;
267}
268
269int wxChoice::GetSelection() const
270{
2d120f83
JS
271 XmString text;
272 char *s;
273 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
274 XtVaGetValues (label,
275 XmNlabelString, &text,
276 NULL);
31528cd3 277
2d120f83
JS
278 if (XmStringGetLtoR (text, XmSTRING_DEFAULT_CHARSET, &s))
279 {
280 int i = 0;
281 for (wxNode * node = m_stringList.First (); node; node = node->Next ())
f97c9854 282 {
2d120f83
JS
283 char *s1 = (char *) node->Data ();
284 if (s1 == s || strcmp (s1, s) == 0)
285 {
286 XmStringFree(text) ;
287 XtFree (s);
288 return i;
289 }
290 else
291 i++;
292 } // for()
31528cd3 293
2d120f83
JS
294 XmStringFree(text) ;
295 XtFree (s);
296 return -1;
297 }
298 XmStringFree(text) ;
299 return -1;
4bb6408c
JS
300}
301
302void wxChoice::SetSelection(int n)
303{
2d120f83 304 m_inSetValue = TRUE;
31528cd3 305
2d120f83
JS
306 wxNode *node = m_stringList.Nth (n);
307 if (node)
f97c9854 308 {
2d120f83 309 Dimension selectionWidth, selectionHeight;
31528cd3 310
2d120f83
JS
311 char *s = (char *) node->Data ();
312 XmString text = XmStringCreateSimple (s);
313 XtVaGetValues ((Widget) m_widgetList[n], XmNwidth, &selectionWidth, XmNheight, &selectionHeight, NULL);
314 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
315 XtVaSetValues (label,
316 XmNlabelString, text,
317 NULL);
318 XmStringFree (text);
319 XtVaSetValues ((Widget) m_buttonWidget,
320 XmNwidth, selectionWidth, XmNheight, selectionHeight,
321 XmNmenuHistory, (Widget) m_widgetList[n], NULL);
f97c9854 322 }
2d120f83 323 m_inSetValue = FALSE;
4bb6408c
JS
324}
325
326int wxChoice::FindString(const wxString& s) const
327{
f97c9854
JS
328 int i = 0;
329 for (wxNode * node = m_stringList.First (); node; node = node->Next ())
330 {
331 char *s1 = (char *) node->Data ();
332 if (s == s1)
333 {
334 return i;
335 }
336 else
337 i++;
338 }
339 return -1;
4bb6408c
JS
340}
341
342wxString wxChoice::GetString(int n) const
343{
2d120f83
JS
344 wxNode *node = m_stringList.Nth (n);
345 if (node)
346 return wxString((char *) node->Data ());
347 else
348 return wxEmptyString;
f97c9854
JS
349}
350
351void wxChoice::SetColumns(int n)
352{
2d120f83 353 if (n<1) n = 1 ;
31528cd3 354
2d120f83
JS
355 short numColumns = n ;
356 Arg args[3];
31528cd3 357
2d120f83
JS
358 XtSetArg(args[0], XmNnumColumns, numColumns);
359 XtSetArg(args[1], XmNpacking, XmPACK_COLUMN);
360 XtSetValues((Widget) m_menuWidget,args,2) ;
f97c9854
JS
361}
362
363int wxChoice::GetColumns(void) const
364{
2d120f83 365 short numColumns ;
31528cd3 366
2d120f83
JS
367 XtVaGetValues((Widget) m_menuWidget,XmNnumColumns,&numColumns,NULL) ;
368 return numColumns ;
f97c9854
JS
369}
370
371void wxChoice::SetFocus()
372{
2d120f83 373 XmProcessTraversal(XtParent((Widget)m_mainWidget), XmTRAVERSE_CURRENT);
4bb6408c
JS
374}
375
bfc6fde4 376void wxChoice::DoSetSize(int x, int y, int width, int height, int sizeFlags)
4bb6408c 377{
f97c9854
JS
378 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
379 bool managed = XtIsManaged((Widget) m_formWidget);
31528cd3 380
f97c9854
JS
381 if (managed)
382 XtUnmanageChild ((Widget) m_formWidget);
31528cd3 383
f97c9854 384 int actualWidth = width, actualHeight = height;
31528cd3 385
f97c9854
JS
386 if (width > -1)
387 {
388 int i;
389 for (i = 0; i < m_noStrings; i++)
390 XtVaSetValues ((Widget) m_widgetList[i], XmNwidth, actualWidth, NULL);
391 XtVaSetValues ((Widget) m_buttonWidget, XmNwidth, actualWidth,
2d120f83 392 NULL);
f97c9854
JS
393 }
394 if (height > -1)
395 {
396 int i;
397 for (i = 0; i < m_noStrings; i++)
398 XtVaSetValues ((Widget) m_widgetList[i], XmNheight, actualHeight, NULL);
399 XtVaSetValues ((Widget) m_buttonWidget, XmNheight, actualHeight,
2d120f83 400 NULL);
f97c9854 401 }
31528cd3 402
f97c9854
JS
403 if (managed)
404 XtManageChild ((Widget) m_formWidget);
405 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
31528cd3 406
bfc6fde4 407 wxControl::DoSetSize (x, y, width, height, sizeFlags);
4bb6408c
JS
408}
409
410wxString wxChoice::GetStringSelection () const
411{
412 int sel = GetSelection ();
413 if (sel > -1)
414 return wxString(this->GetString (sel));
415 else
f97c9854 416 return wxEmptyString;
4bb6408c
JS
417}
418
419bool wxChoice::SetStringSelection (const wxString& s)
420{
421 int sel = FindString (s);
422 if (sel > -1)
2d120f83
JS
423 {
424 SetSelection (sel);
425 return TRUE;
426 }
4bb6408c
JS
427 else
428 return FALSE;
429}
430
431void wxChoice::Command(wxCommandEvent & event)
432{
433 SetSelection (event.GetInt());
434 ProcessCommand (event);
435}
436
f9e02ac7 437void wxChoiceCallback (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
f97c9854
JS
438{
439 wxChoice *item = (wxChoice *) clientData;
440 if (item)
441 {
a4294b78 442 if (item->InSetValue())
f97c9854 443 return;
31528cd3 444
f97c9854
JS
445 char *s = NULL;
446 XtVaGetValues (w, XmNuserData, &s, NULL);
447 if (s)
448 {
55acd85e
JS
449 wxCommandEvent event (wxEVT_COMMAND_CHOICE_SELECTED, item->GetId());
450 event.SetEventObject(item);
f97c9854 451 event.m_commandInt = item->FindString (s);
2d120f83 452 // event.m_commandString = s;
f97c9854
JS
453 item->ProcessCommand (event);
454 }
455 }
456}
457
4b5f3fe6 458void wxChoice::ChangeFont(bool keepOriginalSize)
0d57be45 459{
321db4b6
JS
460 // Note that this causes the widget to be resized back
461 // to its original size! We therefore have to set the size
462 // back again. TODO: a better way in Motif?
da175b2c 463 if (m_font.Ok())
321db4b6
JS
464 {
465 int width, height, width1, height1;
466 GetSize(& width, & height);
31528cd3 467
da175b2c 468 XmFontList fontList = (XmFontList) m_font.GetFontList(1.0, XtDisplay((Widget) m_mainWidget));
321db4b6
JS
469 XtVaSetValues ((Widget) m_mainWidget, XmNfontList, fontList, NULL);
470 XtVaSetValues ((Widget) m_buttonWidget, XmNfontList, fontList, NULL);
31528cd3 471
4b5f3fe6 472 /* TODO: why does this cause a crash in XtWidgetToApplicationContext?
321db4b6
JS
473 int i;
474 for (i = 0; i < m_noStrings; i++)
2d120f83 475 XtVaSetValues ((Widget) m_widgetList[i], XmNfontList, fontList, NULL);
4b5f3fe6 476 */
321db4b6 477 GetSize(& width1, & height1);
4b5f3fe6 478 if (keepOriginalSize && (width != width1 || height != height1))
321db4b6
JS
479 {
480 SetSize(-1, -1, width, height);
481 }
482 }
0d57be45
JS
483}
484
485void wxChoice::ChangeBackgroundColour()
486{
321db4b6
JS
487 DoChangeBackgroundColour(m_formWidget, m_backgroundColour);
488 DoChangeBackgroundColour(m_buttonWidget, m_backgroundColour);
489 DoChangeBackgroundColour(m_menuWidget, m_backgroundColour);
490 int i;
491 for (i = 0; i < m_noStrings; i++)
492 DoChangeBackgroundColour(m_widgetList[i], m_backgroundColour);
0d57be45
JS
493}
494
495void wxChoice::ChangeForegroundColour()
496{
321db4b6
JS
497 DoChangeForegroundColour(m_formWidget, m_foregroundColour);
498 DoChangeForegroundColour(m_buttonWidget, m_foregroundColour);
499 DoChangeForegroundColour(m_menuWidget, m_foregroundColour);
500 int i;
501 for (i = 0; i < m_noStrings; i++)
502 DoChangeForegroundColour(m_widgetList[i], m_foregroundColour);
0d57be45 503}
6adaedf0
JS
504
505
506// These implement functions needed by wxControlWithItems.
507// Unfortunately, they're not all implemented yet.
508
509int wxChoice::GetCount() const
510{
511 return Number();
512}
513
514int wxChoice::DoAppend(const wxString& item)
515{
516 Append(item);
517 return GetCount() - 1;
518}
519
520// Just appends, doesn't yet insert
521void wxChoice::DoInsertItems(const wxArrayString& items, int WXUNUSED(pos))
522{
523 size_t nItems = items.GetCount();
524
525 for ( size_t n = 0; n < nItems; n++ )
526 {
527 Append( items[n]);
528 }
529}
530
531void wxChoice::DoSetItems(const wxArrayString& items, void **WXUNUSED(clientData))
532{
533 Clear();
534 size_t nItems = items.GetCount();
535
536 for ( size_t n = 0; n < nItems; n++ )
537 {
538 Append(items[n]);
539 }
540}
541
542void wxChoice::DoSetFirstItem(int WXUNUSED(n))
543{
544 wxFAIL_MSG( wxT("wxChoice::DoSetFirstItem not implemented") );
545}
546
f6bcfd97 547void wxChoice::DoSetItemClientData(int n, void* clientData)
6adaedf0 548{
f6bcfd97
BP
549 wxNode *node = m_clientList.Nth( n );
550 wxCHECK_RET( node, wxT("invalid index in wxChoice::DoSetItemClientData") );
551
552 node->SetData( (wxObject*) clientData );
6adaedf0
JS
553}
554
f6bcfd97 555void* wxChoice::DoGetItemClientData(int n) const
6adaedf0 556{
f6bcfd97
BP
557 wxNode *node = m_clientList.Nth( n );
558 wxCHECK_MSG( node, NULL, wxT("invalid index in wxChoice::DoGetItemClientData") );
559
560 return node->Data();
6adaedf0
JS
561}
562
f6bcfd97 563void wxChoice::DoSetItemClientObject(int n, wxClientData* clientData)
6adaedf0 564{
f6bcfd97
BP
565 wxNode *node = m_clientList.Nth( n );
566 wxCHECK_RET( node, wxT("invalid index in wxChoice::DoSetItemClientObject") );
567
568 wxClientData *cd = (wxClientData*) node->Data();
569 delete cd;
570
571 node->SetData( (wxObject*) clientData );
6adaedf0
JS
572}
573
f6bcfd97 574wxClientData* wxChoice::DoGetItemClientObject(int n) const
6adaedf0 575{
f6bcfd97
BP
576 wxNode *node = m_clientList.Nth( n );
577 wxCHECK_MSG( node, (wxClientData *)NULL,
578 wxT("invalid index in wxChoice::DoGetItemClientObject") );
579
580 return (wxClientData*) node->Data();
6adaedf0
JS
581}
582
583void wxChoice::Select(int n)
584{
585 SetSelection(n);
586}
587
588void wxChoice::SetString(int WXUNUSED(n), const wxString& WXUNUSED(s))
589{
590 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
591}