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