]> git.saurik.com Git - wxWidgets.git/blame - src/motif/choice.cpp
use wxConvLocal for wxFONTENCODING_SYSTEM/DEFAULT in wxConvertToGTK()
[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
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
8228b893
WS
15#if wxUSE_CHOICE
16
bcd055ae 17#ifdef __VMS
4dff3400
JJ
18#define XtDisplay XTDISPLAY
19#define XtParent XTPARENT
20#endif
21
4bb6408c 22#include "wx/choice.h"
f97c9854 23#include "wx/utils.h"
584ad2a3 24#include "wx/arrstr.h"
f97c9854 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 69 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
312ebad4 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 89 m_menuWidget = (WXWidget) XmCreatePulldownMenu ((Widget) m_formWidget,
f1db433a
VZ
90 wxMOTIF_STR("choiceMenu"),
91 NULL, 0);
31528cd3 92
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
ec75d791
MB
106 XtSetArg (args[argcnt], XmNsubMenuId, (Widget) m_menuWidget); ++argcnt;
107 XtSetArg (args[argcnt], XmNmarginWidth, 0); ++argcnt;
108 XtSetArg (args[argcnt], XmNmarginHeight, 0); ++argcnt;
109 XtSetArg (args[argcnt], XmNpacking, XmPACK_TIGHT); ++argcnt;
110 m_buttonWidget = (WXWidget) XmCreateOptionMenu ((Widget) m_formWidget,
f1db433a 111 wxMOTIF_STR("choiceButton"),
ec75d791 112 args, argcnt);
31528cd3 113
f97c9854 114 m_mainWidget = m_buttonWidget;
31528cd3 115
f97c9854 116 XtManageChild ((Widget) m_buttonWidget);
9838df2c 117
f97c9854
JS
118 // New code from Roland Haenel (roland_haenel@ac.cybercity.de)
119 // Some time ago, I reported a problem with wxChoice-items under
120 // Linux and Motif 2.0 (they caused sporadic GPFs). Now it seems
121 // that I have found the code responsible for this behaviour.
122#if XmVersion >= 1002
123#if XmVersion < 2000
9838df2c
JS
124 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
125 // in controls sample.
dfe1eee3
VZ
126 //
127 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
128 // XtUnmanageChild (optionLabel);
f97c9854
JS
129#endif
130#endif
9838df2c 131
a29ee706
MB
132 wxSize bestSize = GetBestSize();
133 if( size.x > 0 ) bestSize.x = size.x;
134 if( size.y > 0 ) bestSize.y = size.y;
135
f97c9854 136 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
31528cd3 137
312ebad4 138 ChangeFont(false);
3a73cc52 139 ChangeBackgroundColour();
9838df2c 140
ec75d791 141 AttachWidget (parent, m_buttonWidget, m_formWidget,
a29ee706 142 pos.x, pos.y, bestSize.x, bestSize.y);
31528cd3 143
312ebad4 144 return true;
f97c9854
JS
145}
146
584ad2a3
MB
147bool wxChoice::Create(wxWindow *parent, wxWindowID id,
148 const wxPoint& pos,
149 const wxSize& size,
150 const wxArrayString& choices,
151 long style,
152 const wxValidator& validator,
153 const wxString& name)
154{
155 wxCArrayString chs(choices);
156 return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
157 style, validator, name);
158}
159
f97c9854
JS
160wxChoice::~wxChoice()
161{
2d120f83
JS
162 // For some reason destroying the menuWidget
163 // can cause crashes on some machines. It will
164 // be deleted implicitly by deleting the parent form
165 // anyway.
166 // XtDestroyWidget (menuWidget);
31528cd3 167
8aa04e8b
JS
168 if (GetMainWidget())
169 {
170 DetachWidget(GetMainWidget()); // Removes event handlers
b412f9be 171 DetachWidget(m_formWidget);
31528cd3 172
8aa04e8b
JS
173 XtDestroyWidget((Widget) m_formWidget);
174 m_formWidget = (WXWidget) 0;
31528cd3 175
8aa04e8b
JS
176 // Presumably the other widgets have been deleted now, via the form
177 m_mainWidget = (WXWidget) 0;
178 m_buttonWidget = (WXWidget) 0;
179 }
ec75d791
MB
180 if ( HasClientObjectData() )
181 m_clientDataDict.DestroyData();
4bb6408c
JS
182}
183
f94a81c0
MB
184static inline wxChar* MYcopystring(const wxChar* s)
185{
186 wxChar* copy = new wxChar[wxStrlen(s) + 1];
187 return wxStrcpy(copy, s);
188}
189
aa61d352 190int wxChoice::DoInsert(const wxString& item, unsigned int pos)
4bb6408c 191{
f94a81c0 192#ifndef XmNpositionIndex
aa61d352 193 wxCHECK_MSG( pos == GetCount(), -1, wxT("insert not implemented"));
f94a81c0 194#endif
31528cd3 195 Widget w = XtVaCreateManagedWidget (wxStripMenuCodes(item),
8c624a14 196#if wxUSE_GADGETS
2d120f83 197 xmPushButtonGadgetClass, (Widget) m_menuWidget,
f97c9854 198#else
2d120f83 199 xmPushButtonWidgetClass, (Widget) m_menuWidget,
f94a81c0
MB
200#endif
201#ifdef XmNpositionIndex
202 XmNpositionIndex, pos,
f97c9854 203#endif
2d120f83 204 NULL);
31528cd3 205
a8680e3e 206 wxDoChangeBackgroundColour((WXWidget) w, m_backgroundColour);
31528cd3 207
e1aae528
MB
208 if( m_font.Ok() )
209 wxDoChangeFont( w, m_font );
31528cd3 210
f94a81c0 211 m_widgetArray.Insert(w, pos);
31528cd3 212
3a73cc52 213 char mnem = wxFindMnemonic (item);
f6bcfd97
BP
214 if (mnem != 0)
215 XtVaSetValues (w, XmNmnemonic, mnem, NULL);
31528cd3 216
ec75d791
MB
217 XtAddCallback (w, XmNactivateCallback,
218 (XtCallbackProc) wxChoiceCallback,
219 (XtPointer) this);
31528cd3 220
f6bcfd97
BP
221 if (m_noStrings == 0 && m_buttonWidget)
222 {
223 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, w, NULL);
224 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
c13c9657 225 wxXmString text( item );
f6bcfd97 226 XtVaSetValues (label,
c13c9657 227 XmNlabelString, text(),
f6bcfd97 228 NULL);
f6bcfd97 229 }
f94a81c0
MB
230 // need to ditch wxStringList for wxArrayString
231 m_stringList.Insert(pos, MYcopystring(item));
f6bcfd97 232 m_noStrings ++;
c33c81c3 233
f94a81c0 234 return pos;
4bb6408c
JS
235}
236
f94a81c0 237int wxChoice::DoAppend(const wxString& item)
243dbf1a 238{
aa61d352 239 return DoInsert(item, GetCount());
243dbf1a
VZ
240}
241
aa61d352 242void wxChoice::Delete(unsigned int n)
4bb6408c 243{
ec75d791
MB
244 Widget w = (Widget)m_widgetArray[n];
245 XtRemoveCallback(w, XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
246 (XtPointer)this);
ac32ba44 247 m_stringList.Erase(m_stringList.Item(n));
ec75d791
MB
248 m_widgetArray.RemoveAt(size_t(n));
249 m_clientDataDict.Delete(n, HasClientObjectData());
31528cd3 250
ec75d791 251 XtDestroyWidget(w);
aa61d352 252 m_noStrings--;
4bb6408c
JS
253}
254
255void wxChoice::Clear()
256{
f97c9854 257 m_stringList.Clear ();
aa61d352 258 unsigned int i;
f97c9854
JS
259 for (i = 0; i < m_noStrings; i++)
260 {
ec75d791
MB
261 XtRemoveCallback((Widget) m_widgetArray[i],
262 XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
263 (XtPointer)this);
264 XtUnmanageChild ((Widget) m_widgetArray[i]);
265 XtDestroyWidget ((Widget) m_widgetArray[i]);
f97c9854 266 }
ec75d791 267 m_widgetArray.Clear();
f97c9854 268 if (m_buttonWidget)
ec75d791
MB
269 XtVaSetValues ((Widget) m_buttonWidget,
270 XmNmenuHistory, (Widget) NULL,
271 NULL);
f6bcfd97
BP
272
273 if ( HasClientObjectData() )
ec75d791 274 m_clientDataDict.DestroyData();
f6bcfd97 275
4bb6408c
JS
276 m_noStrings = 0;
277}
278
279int wxChoice::GetSelection() const
280{
2d120f83 281 XmString text;
2d120f83
JS
282 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
283 XtVaGetValues (label,
284 XmNlabelString, &text,
285 NULL);
da494b40
MB
286 wxXmString freeMe(text);
287 wxString s = wxXmStringToString( text );
31528cd3 288
11e62fe6 289 if (!s.empty())
2d120f83
JS
290 {
291 int i = 0;
ac32ba44 292 for (wxStringList::compatibility_iterator node = m_stringList.GetFirst ();
ec75d791 293 node; node = node->GetNext ())
f97c9854 294 {
da494b40 295 if (wxStrcmp(node->GetData(), s.c_str()) == 0)
2d120f83 296 {
2d120f83
JS
297 return i;
298 }
299 else
300 i++;
301 } // for()
31528cd3 302
2d120f83
JS
303 return -1;
304 }
2d120f83 305 return -1;
4bb6408c
JS
306}
307
308void wxChoice::SetSelection(int n)
309{
312ebad4 310 m_inSetValue = true;
31528cd3 311
ac32ba44 312 wxStringList::compatibility_iterator node = m_stringList.Item(n);
2d120f83 313 if (node)
f97c9854 314 {
ec75d791 315#if 0
2d120f83 316 Dimension selectionWidth, selectionHeight;
ec75d791 317#endif
fd304d98 318 wxXmString text( node->GetData() );
ec75d791
MB
319// MBN: this seems silly, at best, and causes wxChoices to be clipped:
320// will remove "soon"
321#if 0
322 XtVaGetValues ((Widget) m_widgetArray[n],
323 XmNwidth, &selectionWidth,
324 XmNheight, &selectionHeight,
325 NULL);
326#endif
2d120f83
JS
327 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
328 XtVaSetValues (label,
ec75d791 329 XmNlabelString, text(),
2d120f83 330 NULL);
ec75d791 331#if 0
2d120f83
JS
332 XtVaSetValues ((Widget) m_buttonWidget,
333 XmNwidth, selectionWidth, XmNheight, selectionHeight,
ec75d791
MB
334 XmNmenuHistory, (Widget) m_widgetArray[n], NULL);
335#endif
f97c9854 336 }
312ebad4 337 m_inSetValue = false;
4bb6408c
JS
338}
339
aa61d352 340wxString wxChoice::GetString(unsigned int n) const
4bb6408c 341{
ac32ba44 342 wxStringList::compatibility_iterator node = m_stringList.Item(n);
2d120f83 343 if (node)
ec75d791 344 return node->GetData();
2d120f83
JS
345 else
346 return wxEmptyString;
f97c9854
JS
347}
348
349void wxChoice::SetColumns(int n)
350{
2d120f83 351 if (n<1) n = 1 ;
31528cd3 352
55034339 353 short numColumns = (short)n ;
2d120f83 354 Arg args[3];
31528cd3 355
2d120f83
JS
356 XtSetArg(args[0], XmNnumColumns, numColumns);
357 XtSetArg(args[1], XmNpacking, XmPACK_COLUMN);
358 XtSetValues((Widget) m_menuWidget,args,2) ;
f97c9854
JS
359}
360
361int wxChoice::GetColumns(void) const
362{
2d120f83 363 short numColumns ;
31528cd3 364
2d120f83
JS
365 XtVaGetValues((Widget) m_menuWidget,XmNnumColumns,&numColumns,NULL) ;
366 return numColumns ;
f97c9854
JS
367}
368
369void wxChoice::SetFocus()
370{
2d120f83 371 XmProcessTraversal(XtParent((Widget)m_mainWidget), XmTRAVERSE_CURRENT);
4bb6408c
JS
372}
373
bfc6fde4 374void wxChoice::DoSetSize(int x, int y, int width, int height, int sizeFlags)
4bb6408c 375{
f97c9854
JS
376 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
377 bool managed = XtIsManaged((Widget) m_formWidget);
31528cd3 378
f97c9854
JS
379 if (managed)
380 XtUnmanageChild ((Widget) m_formWidget);
31528cd3 381
3a73cc52
MB
382 int actualWidth = width - WIDTH_OVERHEAD_SUBTRACT,
383 actualHeight = height - HEIGHT_OVERHEAD;
31528cd3 384
f97c9854
JS
385 if (width > -1)
386 {
aa61d352 387 unsigned int i;
f97c9854 388 for (i = 0; i < m_noStrings; i++)
ec75d791
MB
389 XtVaSetValues ((Widget) m_widgetArray[i],
390 XmNwidth, actualWidth,
391 NULL);
f97c9854 392 XtVaSetValues ((Widget) m_buttonWidget, XmNwidth, actualWidth,
2d120f83 393 NULL);
f97c9854
JS
394 }
395 if (height > -1)
396 {
3a73cc52 397#if 0
aa61d352 398 unsigned int i;
f97c9854 399 for (i = 0; i < m_noStrings; i++)
ec75d791
MB
400 XtVaSetValues ((Widget) m_widgetArray[i],
401 XmNheight, actualHeight,
402 NULL);
3a73cc52 403#endif
f97c9854 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
4bb6408c
JS
415void wxChoice::Command(wxCommandEvent & event)
416{
417 SetSelection (event.GetInt());
418 ProcessCommand (event);
419}
420
f9e02ac7 421void wxChoiceCallback (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
f97c9854
JS
422{
423 wxChoice *item = (wxChoice *) clientData;
424 if (item)
425 {
a4294b78 426 if (item->InSetValue())
f97c9854 427 return;
31528cd3 428
ec75d791
MB
429 int n = item->GetWidgets().Index(w);
430 if (n != wxNOT_FOUND)
f97c9854 431 {
ec75d791 432 wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, item->GetId());
55acd85e 433 event.SetEventObject(item);
687706f5
KH
434 event.SetInt(n);
435 event.SetString( item->GetStrings().Item(n)->GetData() );
ec75d791
MB
436 if ( item->HasClientObjectData() )
437 event.SetClientObject( item->GetClientObject(n) );
438 else if ( item->HasClientUntypedData() )
439 event.SetClientData( item->GetClientData(n) );
f97c9854
JS
440 item->ProcessCommand (event);
441 }
442 }
443}
444
4b5f3fe6 445void wxChoice::ChangeFont(bool keepOriginalSize)
0d57be45 446{
321db4b6
JS
447 // Note that this causes the widget to be resized back
448 // to its original size! We therefore have to set the size
449 // back again. TODO: a better way in Motif?
da175b2c 450 if (m_font.Ok())
321db4b6 451 {
73608949 452 Display* dpy = XtDisplay((Widget) m_mainWidget);
321db4b6
JS
453 int width, height, width1, height1;
454 GetSize(& width, & height);
31528cd3 455
da494b40
MB
456 WXString fontTag = wxFont::GetFontTag();
457
73608949
MB
458 XtVaSetValues ((Widget) m_formWidget,
459 fontTag, m_font.GetFontTypeC(dpy),
460 NULL);
461 XtVaSetValues ((Widget) m_buttonWidget,
462 fontTag, m_font.GetFontTypeC(dpy),
463 NULL);
31528cd3 464
aa61d352 465 for( unsigned int i = 0; i < m_noStrings; ++i )
ec75d791 466 XtVaSetValues( (Widget)m_widgetArray[i],
73608949 467 fontTag, m_font.GetFontTypeC(dpy),
ec75d791 468 NULL );
312ebad4 469
321db4b6 470 GetSize(& width1, & height1);
4b5f3fe6 471 if (keepOriginalSize && (width != width1 || height != height1))
321db4b6 472 {
312ebad4 473 SetSize(wxDefaultCoord, wxDefaultCoord, width, height);
321db4b6
JS
474 }
475 }
0d57be45
JS
476}
477
478void wxChoice::ChangeBackgroundColour()
479{
a8680e3e
MB
480 wxDoChangeBackgroundColour(m_formWidget, m_backgroundColour);
481 wxDoChangeBackgroundColour(m_buttonWidget, m_backgroundColour);
482 wxDoChangeBackgroundColour(m_menuWidget, m_backgroundColour);
aa61d352 483 unsigned int i;
321db4b6 484 for (i = 0; i < m_noStrings; i++)
a8680e3e 485 wxDoChangeBackgroundColour(m_widgetArray[i], m_backgroundColour);
0d57be45
JS
486}
487
488void wxChoice::ChangeForegroundColour()
489{
a8680e3e
MB
490 wxDoChangeForegroundColour(m_formWidget, m_foregroundColour);
491 wxDoChangeForegroundColour(m_buttonWidget, m_foregroundColour);
492 wxDoChangeForegroundColour(m_menuWidget, m_foregroundColour);
aa61d352 493 unsigned int i;
321db4b6 494 for (i = 0; i < m_noStrings; i++)
a8680e3e 495 wxDoChangeForegroundColour(m_widgetArray[i], m_foregroundColour);
0d57be45 496}
6adaedf0 497
aa61d352 498unsigned int wxChoice::GetCount() const
6adaedf0 499{
ec75d791 500 return m_noStrings;
6adaedf0
JS
501}
502
aa61d352 503void wxChoice::DoSetItemClientData(unsigned int n, void* clientData)
6adaedf0 504{
312ebad4 505 m_clientDataDict.Set(n, (wxClientData*)clientData, false);
6adaedf0
JS
506}
507
aa61d352 508void* wxChoice::DoGetItemClientData(unsigned int n) const
6adaedf0 509{
ec75d791 510 return (void*)m_clientDataDict.Get(n);
6adaedf0
JS
511}
512
aa61d352 513void wxChoice::DoSetItemClientObject(unsigned int n, wxClientData* clientData)
6adaedf0 514{
ec75d791 515 // don't delete, wxItemContainer does that for us
312ebad4 516 m_clientDataDict.Set(n, clientData, false);
6adaedf0
JS
517}
518
aa61d352 519wxClientData* wxChoice::DoGetItemClientObject(unsigned int n) const
6adaedf0 520{
ec75d791 521 return m_clientDataDict.Get(n);
6adaedf0
JS
522}
523
aa61d352 524void wxChoice::SetString(unsigned int WXUNUSED(n), const wxString& WXUNUSED(s))
6adaedf0 525{
ec75d791 526 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
6adaedf0
JS
527}
528
ec75d791 529wxSize wxChoice::GetItemsSize() const
6adaedf0 530{
ec75d791 531 int x, y, mx = 0, my = 0;
f6bcfd97 532
ec75d791
MB
533 // get my
534 GetTextExtent( "|", &x, &my );
f6bcfd97 535
ac32ba44 536 wxStringList::compatibility_iterator curr = m_stringList.GetFirst();
ec75d791
MB
537 while( curr )
538 {
539 GetTextExtent( curr->GetData(), &x, &y );
540 mx = wxMax( mx, x );
541 my = wxMax( my, y );
542 curr = curr->GetNext();
543 }
6adaedf0 544
ec75d791 545 return wxSize( mx, my );
6adaedf0
JS
546}
547
ec75d791 548wxSize wxChoice::DoGetBestSize() const
6adaedf0 549{
ec75d791
MB
550 wxSize items = GetItemsSize();
551 // FIXME arbitrary constants
3a73cc52
MB
552 return wxSize( ( items.x ? items.x + WIDTH_OVERHEAD : 120 ),
553 items.y + HEIGHT_OVERHEAD );
6adaedf0 554}
312ebad4
WS
555
556#endif // wxUSE_CHOICE