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