]> git.saurik.com Git - wxWidgets.git/blame - src/motif/choice.cpp
Trace module initialization and cleanup.
[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
312ebad4 9// Licence: wxWindows licence
4bb6408c
JS
10/////////////////////////////////////////////////////////////////////////////
11
1248b41f
MB
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
bcd055ae 15#ifdef __VMS
4dff3400
JJ
16#define XtDisplay XTDISPLAY
17#define XtParent XTPARENT
18#endif
19
f6045f99
GD
20#include "wx/defs.h"
21
312ebad4
WS
22#if wxUSE_CHOICE
23
4bb6408c 24#include "wx/choice.h"
f97c9854 25#include "wx/utils.h"
584ad2a3 26#include "wx/arrstr.h"
f97c9854 27
338dd992
JJ
28#ifdef __VMS__
29#pragma message disable nosimpint
30#endif
f97c9854
JS
31#include <Xm/Xm.h>
32#include <Xm/PushBG.h>
33#include <Xm/PushB.h>
34#include <Xm/RowColumn.h>
338dd992
JJ
35#ifdef __VMS__
36#pragma message enable nosimpint
37#endif
f97c9854
JS
38
39#include "wx/motif/private.h"
4bb6408c 40
3a73cc52
MB
41#define WIDTH_OVERHEAD 48
42#define WIDTH_OVERHEAD_SUBTRACT 40
43#define HEIGHT_OVERHEAD 15
44
4bb6408c 45IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
4bb6408c 46
f97c9854 47void wxChoiceCallback (Widget w, XtPointer clientData,
2d120f83 48 XtPointer ptr);
f97c9854
JS
49
50wxChoice::wxChoice()
51{
ec75d791
MB
52 Init();
53}
54
55void wxChoice::Init()
56{
f97c9854
JS
57 m_noStrings = 0;
58 m_buttonWidget = (WXWidget) 0;
59 m_menuWidget = (WXWidget) 0;
f97c9854 60 m_formWidget = (WXWidget) 0;
f97c9854
JS
61}
62
4bb6408c 63bool wxChoice::Create(wxWindow *parent, wxWindowID id,
2d120f83
JS
64 const wxPoint& pos,
65 const wxSize& size,
66 int n, const wxString choices[],
67 long style,
68 const wxValidator& validator,
69 const wxString& name)
4bb6408c 70{
ec75d791 71 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
312ebad4 72 return false;
31528cd3 73
f97c9854 74 Widget parentWidget = (Widget) parent->GetClientWidget();
31528cd3
VZ
75
76 m_formWidget = (WXWidget) XtVaCreateManagedWidget(name.c_str(),
2d120f83
JS
77 xmRowColumnWidgetClass, parentWidget,
78 XmNmarginHeight, 0,
79 XmNmarginWidth, 0,
80 XmNpacking, XmPACK_TIGHT,
81 XmNorientation, XmHORIZONTAL,
3a73cc52
MB
82 XmNresizeWidth, False,
83 XmNresizeHeight, False,
2d120f83 84 NULL);
31528cd3 85
f97c9854 86 XtVaSetValues ((Widget) m_formWidget, XmNspacing, 0, NULL);
31528cd3 87
2d120f83 88 /*
f97c9854
JS
89 * Create the popup menu
90 */
ec75d791 91 m_menuWidget = (WXWidget) XmCreatePulldownMenu ((Widget) m_formWidget,
f1db433a
VZ
92 wxMOTIF_STR("choiceMenu"),
93 NULL, 0);
31528cd3 94
f97c9854
JS
95 if (n > 0)
96 {
97 int i;
98 for (i = 0; i < n; i++)
99 Append (choices[i]);
100 }
31528cd3 101
2d120f83 102 /*
f97c9854
JS
103 * Create button
104 */
105 Arg args[10];
106 Cardinal argcnt = 0;
31528cd3 107
ec75d791
MB
108 XtSetArg (args[argcnt], XmNsubMenuId, (Widget) m_menuWidget); ++argcnt;
109 XtSetArg (args[argcnt], XmNmarginWidth, 0); ++argcnt;
110 XtSetArg (args[argcnt], XmNmarginHeight, 0); ++argcnt;
111 XtSetArg (args[argcnt], XmNpacking, XmPACK_TIGHT); ++argcnt;
112 m_buttonWidget = (WXWidget) XmCreateOptionMenu ((Widget) m_formWidget,
f1db433a 113 wxMOTIF_STR("choiceButton"),
ec75d791 114 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
a29ee706
MB
134 wxSize bestSize = GetBestSize();
135 if( size.x > 0 ) bestSize.x = size.x;
136 if( size.y > 0 ) bestSize.y = size.y;
137
f97c9854 138 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
31528cd3 139
312ebad4 140 ChangeFont(false);
3a73cc52 141 ChangeBackgroundColour();
9838df2c 142
ec75d791 143 AttachWidget (parent, m_buttonWidget, m_formWidget,
a29ee706 144 pos.x, pos.y, bestSize.x, bestSize.y);
31528cd3 145
312ebad4 146 return true;
f97c9854
JS
147}
148
584ad2a3
MB
149bool wxChoice::Create(wxWindow *parent, wxWindowID id,
150 const wxPoint& pos,
151 const wxSize& size,
152 const wxArrayString& choices,
153 long style,
154 const wxValidator& validator,
155 const wxString& name)
156{
157 wxCArrayString chs(choices);
158 return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
159 style, validator, name);
160}
161
f97c9854
JS
162wxChoice::~wxChoice()
163{
2d120f83
JS
164 // For some reason destroying the menuWidget
165 // can cause crashes on some machines. It will
166 // be deleted implicitly by deleting the parent form
167 // anyway.
168 // XtDestroyWidget (menuWidget);
31528cd3 169
8aa04e8b
JS
170 if (GetMainWidget())
171 {
172 DetachWidget(GetMainWidget()); // Removes event handlers
b412f9be 173 DetachWidget(m_formWidget);
31528cd3 174
8aa04e8b
JS
175 XtDestroyWidget((Widget) m_formWidget);
176 m_formWidget = (WXWidget) 0;
31528cd3 177
8aa04e8b
JS
178 // Presumably the other widgets have been deleted now, via the form
179 m_mainWidget = (WXWidget) 0;
180 m_buttonWidget = (WXWidget) 0;
181 }
ec75d791
MB
182 if ( HasClientObjectData() )
183 m_clientDataDict.DestroyData();
4bb6408c
JS
184}
185
c33c81c3 186int wxChoice::DoAppend(const wxString& item)
4bb6408c 187{
31528cd3 188 Widget w = XtVaCreateManagedWidget (wxStripMenuCodes(item),
8c624a14 189#if wxUSE_GADGETS
2d120f83 190 xmPushButtonGadgetClass, (Widget) m_menuWidget,
f97c9854 191#else
2d120f83 192 xmPushButtonWidgetClass, (Widget) m_menuWidget,
f97c9854 193#endif
2d120f83 194 NULL);
31528cd3 195
a8680e3e 196 wxDoChangeBackgroundColour((WXWidget) w, m_backgroundColour);
31528cd3 197
e1aae528
MB
198 if( m_font.Ok() )
199 wxDoChangeFont( w, m_font );
31528cd3 200
ec75d791 201 m_widgetArray.Add(w);
31528cd3 202
3a73cc52 203 char mnem = wxFindMnemonic (item);
f6bcfd97
BP
204 if (mnem != 0)
205 XtVaSetValues (w, XmNmnemonic, mnem, NULL);
31528cd3 206
ec75d791
MB
207 XtAddCallback (w, XmNactivateCallback,
208 (XtCallbackProc) wxChoiceCallback,
209 (XtPointer) this);
31528cd3 210
f6bcfd97
BP
211 if (m_noStrings == 0 && m_buttonWidget)
212 {
213 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, w, NULL);
214 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
c13c9657 215 wxXmString text( item );
f6bcfd97 216 XtVaSetValues (label,
c13c9657 217 XmNlabelString, text(),
f6bcfd97 218 NULL);
f6bcfd97 219 }
ec75d791 220 m_stringList.Add(item);
f6bcfd97 221 m_noStrings ++;
c33c81c3 222
ec75d791 223 return GetCount() - 1;
4bb6408c
JS
224}
225
243dbf1a
VZ
226int wxChoice::DoInsert(const wxString& item, int pos)
227{
312ebad4 228 wxCHECK_MSG(false, -1, wxT("insert not implemented"));
243dbf1a
VZ
229
230// wxCHECK_MSG((pos>=0) && (pos<=GetCount()), -1, wxT("invalid index"));
231// if (pos == GetCount()) return DoAppend(item);
232}
233
ec75d791 234void wxChoice::Delete(int n)
4bb6408c 235{
ec75d791
MB
236 Widget w = (Widget)m_widgetArray[n];
237 XtRemoveCallback(w, XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
238 (XtPointer)this);
ac32ba44 239 m_stringList.Erase(m_stringList.Item(n));
ec75d791
MB
240 m_widgetArray.RemoveAt(size_t(n));
241 m_clientDataDict.Delete(n, HasClientObjectData());
31528cd3 242
ec75d791 243 XtDestroyWidget(w);
4bb6408c
JS
244 m_noStrings --;
245}
246
247void wxChoice::Clear()
248{
f97c9854 249 m_stringList.Clear ();
fd304d98 250 size_t i;
f97c9854
JS
251 for (i = 0; i < m_noStrings; i++)
252 {
ec75d791
MB
253 XtRemoveCallback((Widget) m_widgetArray[i],
254 XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
255 (XtPointer)this);
256 XtUnmanageChild ((Widget) m_widgetArray[i]);
257 XtDestroyWidget ((Widget) m_widgetArray[i]);
f97c9854 258 }
ec75d791 259 m_widgetArray.Clear();
f97c9854 260 if (m_buttonWidget)
ec75d791
MB
261 XtVaSetValues ((Widget) m_buttonWidget,
262 XmNmenuHistory, (Widget) NULL,
263 NULL);
f6bcfd97
BP
264
265 if ( HasClientObjectData() )
ec75d791 266 m_clientDataDict.DestroyData();
f6bcfd97 267
4bb6408c
JS
268 m_noStrings = 0;
269}
270
271int wxChoice::GetSelection() const
272{
2d120f83 273 XmString text;
2d120f83
JS
274 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
275 XtVaGetValues (label,
276 XmNlabelString, &text,
277 NULL);
da494b40
MB
278 wxXmString freeMe(text);
279 wxString s = wxXmStringToString( text );
31528cd3 280
da494b40 281 if (!s.IsEmpty())
2d120f83
JS
282 {
283 int i = 0;
ac32ba44 284 for (wxStringList::compatibility_iterator node = m_stringList.GetFirst ();
ec75d791 285 node; node = node->GetNext ())
f97c9854 286 {
da494b40 287 if (wxStrcmp(node->GetData(), s.c_str()) == 0)
2d120f83 288 {
2d120f83
JS
289 return i;
290 }
291 else
292 i++;
293 } // for()
31528cd3 294
2d120f83
JS
295 return -1;
296 }
2d120f83 297 return -1;
4bb6408c
JS
298}
299
300void wxChoice::SetSelection(int n)
301{
312ebad4 302 m_inSetValue = true;
31528cd3 303
ac32ba44 304 wxStringList::compatibility_iterator node = m_stringList.Item(n);
2d120f83 305 if (node)
f97c9854 306 {
ec75d791 307#if 0
2d120f83 308 Dimension selectionWidth, selectionHeight;
ec75d791 309#endif
fd304d98 310 wxXmString text( node->GetData() );
ec75d791
MB
311// MBN: this seems silly, at best, and causes wxChoices to be clipped:
312// will remove "soon"
313#if 0
314 XtVaGetValues ((Widget) m_widgetArray[n],
315 XmNwidth, &selectionWidth,
316 XmNheight, &selectionHeight,
317 NULL);
318#endif
2d120f83
JS
319 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
320 XtVaSetValues (label,
ec75d791 321 XmNlabelString, text(),
2d120f83 322 NULL);
ec75d791 323#if 0
2d120f83
JS
324 XtVaSetValues ((Widget) m_buttonWidget,
325 XmNwidth, selectionWidth, XmNheight, selectionHeight,
ec75d791
MB
326 XmNmenuHistory, (Widget) m_widgetArray[n], NULL);
327#endif
f97c9854 328 }
312ebad4 329 m_inSetValue = false;
4bb6408c
JS
330}
331
332int wxChoice::FindString(const wxString& s) const
333{
f97c9854 334 int i = 0;
ac32ba44 335 for (wxStringList::compatibility_iterator node = m_stringList.GetFirst();
ec75d791 336 node; node = node->GetNext ())
f97c9854 337 {
ec75d791 338 if (s == node->GetData())
f97c9854 339 return i;
ec75d791
MB
340
341 i++;
f97c9854 342 }
ec75d791 343
312ebad4 344 return wxNOT_FOUND;
4bb6408c
JS
345}
346
347wxString wxChoice::GetString(int n) const
348{
ac32ba44 349 wxStringList::compatibility_iterator node = m_stringList.Item(n);
2d120f83 350 if (node)
ec75d791 351 return node->GetData();
2d120f83
JS
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
3a73cc52
MB
389 int actualWidth = width - WIDTH_OVERHEAD_SUBTRACT,
390 actualHeight = height - HEIGHT_OVERHEAD;
31528cd3 391
f97c9854
JS
392 if (width > -1)
393 {
fd304d98 394 size_t i;
f97c9854 395 for (i = 0; i < m_noStrings; i++)
ec75d791
MB
396 XtVaSetValues ((Widget) m_widgetArray[i],
397 XmNwidth, actualWidth,
398 NULL);
f97c9854 399 XtVaSetValues ((Widget) m_buttonWidget, XmNwidth, actualWidth,
2d120f83 400 NULL);
f97c9854
JS
401 }
402 if (height > -1)
403 {
3a73cc52 404#if 0
fd304d98 405 size_t i;
f97c9854 406 for (i = 0; i < m_noStrings; i++)
ec75d791
MB
407 XtVaSetValues ((Widget) m_widgetArray[i],
408 XmNheight, actualHeight,
409 NULL);
3a73cc52 410#endif
f97c9854 411 XtVaSetValues ((Widget) m_buttonWidget, XmNheight, actualHeight,
2d120f83 412 NULL);
f97c9854 413 }
31528cd3 414
f97c9854
JS
415 if (managed)
416 XtManageChild ((Widget) m_formWidget);
417 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
31528cd3 418
bfc6fde4 419 wxControl::DoSetSize (x, y, width, height, sizeFlags);
4bb6408c
JS
420}
421
4bb6408c
JS
422void wxChoice::Command(wxCommandEvent & event)
423{
424 SetSelection (event.GetInt());
425 ProcessCommand (event);
426}
427
f9e02ac7 428void wxChoiceCallback (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
f97c9854
JS
429{
430 wxChoice *item = (wxChoice *) clientData;
431 if (item)
432 {
a4294b78 433 if (item->InSetValue())
f97c9854 434 return;
31528cd3 435
ec75d791
MB
436 int n = item->GetWidgets().Index(w);
437 if (n != wxNOT_FOUND)
f97c9854 438 {
ec75d791 439 wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, item->GetId());
55acd85e 440 event.SetEventObject(item);
687706f5
KH
441 event.SetInt(n);
442 event.SetString( item->GetStrings().Item(n)->GetData() );
ec75d791
MB
443 if ( item->HasClientObjectData() )
444 event.SetClientObject( item->GetClientObject(n) );
445 else if ( item->HasClientUntypedData() )
446 event.SetClientData( item->GetClientData(n) );
f97c9854
JS
447 item->ProcessCommand (event);
448 }
449 }
450}
451
4b5f3fe6 452void wxChoice::ChangeFont(bool keepOriginalSize)
0d57be45 453{
321db4b6
JS
454 // Note that this causes the widget to be resized back
455 // to its original size! We therefore have to set the size
456 // back again. TODO: a better way in Motif?
da175b2c 457 if (m_font.Ok())
321db4b6 458 {
73608949 459 Display* dpy = XtDisplay((Widget) m_mainWidget);
321db4b6
JS
460 int width, height, width1, height1;
461 GetSize(& width, & height);
31528cd3 462
da494b40
MB
463 WXString fontTag = wxFont::GetFontTag();
464
73608949
MB
465 XtVaSetValues ((Widget) m_formWidget,
466 fontTag, m_font.GetFontTypeC(dpy),
467 NULL);
468 XtVaSetValues ((Widget) m_buttonWidget,
469 fontTag, m_font.GetFontTypeC(dpy),
470 NULL);
31528cd3 471
ec75d791
MB
472 for( size_t i = 0; i < m_noStrings; ++i )
473 XtVaSetValues( (Widget)m_widgetArray[i],
73608949 474 fontTag, m_font.GetFontTypeC(dpy),
ec75d791 475 NULL );
312ebad4 476
321db4b6 477 GetSize(& width1, & height1);
4b5f3fe6 478 if (keepOriginalSize && (width != width1 || height != height1))
321db4b6 479 {
312ebad4 480 SetSize(wxDefaultCoord, wxDefaultCoord, width, height);
321db4b6
JS
481 }
482 }
0d57be45
JS
483}
484
485void wxChoice::ChangeBackgroundColour()
486{
a8680e3e
MB
487 wxDoChangeBackgroundColour(m_formWidget, m_backgroundColour);
488 wxDoChangeBackgroundColour(m_buttonWidget, m_backgroundColour);
489 wxDoChangeBackgroundColour(m_menuWidget, m_backgroundColour);
fd304d98 490 size_t i;
321db4b6 491 for (i = 0; i < m_noStrings; i++)
a8680e3e 492 wxDoChangeBackgroundColour(m_widgetArray[i], m_backgroundColour);
0d57be45
JS
493}
494
495void wxChoice::ChangeForegroundColour()
496{
a8680e3e
MB
497 wxDoChangeForegroundColour(m_formWidget, m_foregroundColour);
498 wxDoChangeForegroundColour(m_buttonWidget, m_foregroundColour);
499 wxDoChangeForegroundColour(m_menuWidget, m_foregroundColour);
fd304d98 500 size_t i;
321db4b6 501 for (i = 0; i < m_noStrings; i++)
a8680e3e 502 wxDoChangeForegroundColour(m_widgetArray[i], m_foregroundColour);
0d57be45 503}
6adaedf0 504
6adaedf0
JS
505int wxChoice::GetCount() const
506{
ec75d791 507 return m_noStrings;
6adaedf0
JS
508}
509
ec75d791 510void wxChoice::DoSetItemClientData(int n, void* clientData)
6adaedf0 511{
312ebad4 512 m_clientDataDict.Set(n, (wxClientData*)clientData, false);
6adaedf0
JS
513}
514
ec75d791 515void* wxChoice::DoGetItemClientData(int n) const
6adaedf0 516{
ec75d791 517 return (void*)m_clientDataDict.Get(n);
6adaedf0
JS
518}
519
ec75d791 520void wxChoice::DoSetItemClientObject(int n, wxClientData* clientData)
6adaedf0 521{
ec75d791 522 // don't delete, wxItemContainer does that for us
312ebad4 523 m_clientDataDict.Set(n, clientData, false);
6adaedf0
JS
524}
525
ec75d791 526wxClientData* wxChoice::DoGetItemClientObject(int n) const
6adaedf0 527{
ec75d791 528 return m_clientDataDict.Get(n);
6adaedf0
JS
529}
530
ec75d791 531void wxChoice::SetString(int WXUNUSED(n), const wxString& WXUNUSED(s))
6adaedf0 532{
ec75d791 533 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
6adaedf0
JS
534}
535
ec75d791 536wxSize wxChoice::GetItemsSize() const
6adaedf0 537{
ec75d791 538 int x, y, mx = 0, my = 0;
f6bcfd97 539
ec75d791
MB
540 // get my
541 GetTextExtent( "|", &x, &my );
f6bcfd97 542
ac32ba44 543 wxStringList::compatibility_iterator curr = m_stringList.GetFirst();
ec75d791
MB
544 while( curr )
545 {
546 GetTextExtent( curr->GetData(), &x, &y );
547 mx = wxMax( mx, x );
548 my = wxMax( my, y );
549 curr = curr->GetNext();
550 }
6adaedf0 551
ec75d791 552 return wxSize( mx, my );
6adaedf0
JS
553}
554
ec75d791 555wxSize wxChoice::DoGetBestSize() const
6adaedf0 556{
ec75d791
MB
557 wxSize items = GetItemsSize();
558 // FIXME arbitrary constants
3a73cc52
MB
559 return wxSize( ( items.x ? items.x + WIDTH_OVERHEAD : 120 ),
560 items.y + HEIGHT_OVERHEAD );
6adaedf0 561}
312ebad4
WS
562
563#endif // wxUSE_CHOICE