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