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