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