]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/motif/choice.cpp
don't use deprecated toolbar API
[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_noStrings = 0;
54 m_buttonWidget = (WXWidget) 0;
55 m_menuWidget = (WXWidget) 0;
56 m_formWidget = (WXWidget) 0;
57}
58
59bool wxChoice::Create(wxWindow *parent, wxWindowID id,
60 const wxPoint& pos,
61 const wxSize& size,
62 int n, const wxString choices[],
63 long style,
64 const wxValidator& validator,
65 const wxString& name)
66{
67 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
68 return false;
69 PreCreation();
70
71 Widget parentWidget = (Widget) parent->GetClientWidget();
72
73 m_formWidget = (WXWidget) XtVaCreateManagedWidget(name.c_str(),
74 xmRowColumnWidgetClass, parentWidget,
75 XmNmarginHeight, 0,
76 XmNmarginWidth, 0,
77 XmNpacking, XmPACK_TIGHT,
78 XmNorientation, XmHORIZONTAL,
79 XmNresizeWidth, False,
80 XmNresizeHeight, False,
81 NULL);
82
83 XtVaSetValues ((Widget) m_formWidget, XmNspacing, 0, NULL);
84
85 /*
86 * Create the popup menu
87 */
88 m_menuWidget = (WXWidget) XmCreatePulldownMenu ((Widget) m_formWidget,
89 wxMOTIF_STR("choiceMenu"),
90 NULL, 0);
91
92 if (n > 0)
93 {
94 int i;
95 for (i = 0; i < n; i++)
96 Append (choices[i]);
97 }
98
99 /*
100 * Create button
101 */
102 Arg args[10];
103 Cardinal argcnt = 0;
104
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 wxMOTIF_STR("choiceButton"),
111 args, argcnt);
112
113 m_mainWidget = m_buttonWidget;
114
115 XtManageChild ((Widget) m_buttonWidget);
116
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
123 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
124 // in controls sample.
125 //
126 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
127 // XtUnmanageChild (optionLabel);
128#endif
129#endif
130
131 wxSize bestSize = GetBestSize();
132 if( size.x > 0 ) bestSize.x = size.x;
133 if( size.y > 0 ) bestSize.y = size.y;
134
135 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
136
137 PostCreation();
138 AttachWidget (parent, m_buttonWidget, m_formWidget,
139 pos.x, pos.y, bestSize.x, bestSize.y);
140
141 return true;
142}
143
144bool wxChoice::Create(wxWindow *parent, wxWindowID id,
145 const wxPoint& pos,
146 const wxSize& size,
147 const wxArrayString& choices,
148 long style,
149 const wxValidator& validator,
150 const wxString& name)
151{
152 wxCArrayString chs(choices);
153 return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
154 style, validator, name);
155}
156
157wxChoice::~wxChoice()
158{
159 // For some reason destroying the menuWidget
160 // can cause crashes on some machines. It will
161 // be deleted implicitly by deleting the parent form
162 // anyway.
163 // XtDestroyWidget (menuWidget);
164
165 if (GetMainWidget())
166 {
167 DetachWidget(GetMainWidget()); // Removes event handlers
168 DetachWidget(m_formWidget);
169
170 XtDestroyWidget((Widget) m_formWidget);
171 m_formWidget = (WXWidget) 0;
172
173 // Presumably the other widgets have been deleted now, via the form
174 m_mainWidget = (WXWidget) 0;
175 m_buttonWidget = (WXWidget) 0;
176 }
177}
178
179static inline wxChar* MYcopystring(const wxChar* s)
180{
181 wxChar* copy = new wxChar[wxStrlen(s) + 1];
182 return wxStrcpy(copy, s);
183}
184
185// TODO auto-sorting is not supported by the code
186int wxChoice::DoInsertItems(const wxArrayStringsAdapter& items,
187 unsigned int pos,
188 void **clientData, wxClientDataType type)
189{
190#ifndef XmNpositionIndex
191 wxCHECK_MSG( pos == GetCount(), -1, wxT("insert not implemented"));
192#endif
193
194 const unsigned int numItems = items.GetCount();
195 AllocClientData(numItems);
196 for( unsigned int i = 0; i < numItems; ++i, ++pos )
197 {
198 Widget w = XtVaCreateManagedWidget (GetLabelText(items[i]),
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 (items[i]);
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( items[i] );
229 XtVaSetValues (label,
230 XmNlabelString, text(),
231 NULL);
232 }
233 // need to ditch wxStringList for wxArrayString
234 m_stringList.Insert(pos, MYcopystring(items[i]));
235 m_noStrings ++;
236
237 InsertNewItemClientData(pos, clientData, i, type);
238 }
239
240 return pos - 1;
241}
242
243void wxChoice::DoDeleteOneItem(unsigned int n)
244{
245 Widget w = (Widget)m_widgetArray[n];
246 XtRemoveCallback(w, XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
247 (XtPointer)this);
248 m_stringList.Erase(m_stringList.Item(n));
249 m_widgetArray.RemoveAt(size_t(n));
250 wxChoiceBase::DoDeleteOneItem(n);
251
252 XtDestroyWidget(w);
253 m_noStrings--;
254}
255
256void wxChoice::DoClear()
257{
258 m_stringList.Clear ();
259 unsigned int i;
260 for (i = 0; i < m_noStrings; i++)
261 {
262 XtRemoveCallback((Widget) m_widgetArray[i],
263 XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
264 (XtPointer)this);
265 XtUnmanageChild ((Widget) m_widgetArray[i]);
266 XtDestroyWidget ((Widget) m_widgetArray[i]);
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 m_noStrings = 0;
277}
278
279int wxChoice::GetSelection() const
280{
281 XmString text;
282 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
283 XtVaGetValues (label,
284 XmNlabelString, &text,
285 NULL);
286 wxXmString freeMe(text);
287 wxString s = wxXmStringToString( text );
288
289 if (!s.empty())
290 {
291 int i = 0;
292 for (wxStringList::compatibility_iterator node = m_stringList.GetFirst ();
293 node; node = node->GetNext ())
294 {
295 if (wxStrcmp(node->GetData(), s.c_str()) == 0)
296 {
297 return i;
298 }
299 else
300 i++;
301 } // for()
302
303 return -1;
304 }
305 return -1;
306}
307
308void wxChoice::SetSelection(int n)
309{
310 m_inSetValue = true;
311
312 wxStringList::compatibility_iterator node = m_stringList.Item(n);
313 if (node)
314 {
315#if 0
316 Dimension selectionWidth, selectionHeight;
317#endif
318 wxXmString text( node->GetData() );
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
327 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
328 XtVaSetValues (label,
329 XmNlabelString, text(),
330 NULL);
331#if 0
332 XtVaSetValues ((Widget) m_buttonWidget,
333 XmNwidth, selectionWidth, XmNheight, selectionHeight,
334 XmNmenuHistory, (Widget) m_widgetArray[n], NULL);
335#endif
336 }
337 m_inSetValue = false;
338}
339
340wxString wxChoice::GetString(unsigned int n) const
341{
342 wxStringList::compatibility_iterator node = m_stringList.Item(n);
343 if (node)
344 return node->GetData();
345 else
346 return wxEmptyString;
347}
348
349void wxChoice::SetColumns(int n)
350{
351 if (n<1) n = 1 ;
352
353 short numColumns = (short)n ;
354 Arg args[3];
355
356 XtSetArg(args[0], XmNnumColumns, numColumns);
357 XtSetArg(args[1], XmNpacking, XmPACK_COLUMN);
358 XtSetValues((Widget) m_menuWidget,args,2) ;
359}
360
361int wxChoice::GetColumns(void) const
362{
363 short numColumns ;
364
365 XtVaGetValues((Widget) m_menuWidget,XmNnumColumns,&numColumns,NULL) ;
366 return numColumns ;
367}
368
369void wxChoice::SetFocus()
370{
371 XmProcessTraversal(XtParent((Widget)m_mainWidget), XmTRAVERSE_CURRENT);
372}
373
374void wxChoice::DoSetSize(int x, int y, int width, int height, int sizeFlags)
375{
376 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
377 bool managed = XtIsManaged((Widget) m_formWidget);
378
379 if (managed)
380 XtUnmanageChild ((Widget) m_formWidget);
381
382 int actualWidth = width - WIDTH_OVERHEAD_SUBTRACT,
383 actualHeight = height - HEIGHT_OVERHEAD;
384
385 if (width > -1)
386 {
387 unsigned int i;
388 for (i = 0; i < m_noStrings; i++)
389 XtVaSetValues ((Widget) m_widgetArray[i],
390 XmNwidth, actualWidth,
391 NULL);
392 XtVaSetValues ((Widget) m_buttonWidget, XmNwidth, actualWidth,
393 NULL);
394 }
395 if (height > -1)
396 {
397#if 0
398 unsigned int i;
399 for (i = 0; i < m_noStrings; i++)
400 XtVaSetValues ((Widget) m_widgetArray[i],
401 XmNheight, actualHeight,
402 NULL);
403#endif
404 XtVaSetValues ((Widget) m_buttonWidget, XmNheight, actualHeight,
405 NULL);
406 }
407
408 if (managed)
409 XtManageChild ((Widget) m_formWidget);
410 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
411
412 wxControl::DoSetSize (x, y, width, height, sizeFlags);
413}
414
415void wxChoice::Command(wxCommandEvent & event)
416{
417 SetSelection (event.GetInt());
418 ProcessCommand (event);
419}
420
421void wxChoiceCallback (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
422{
423 wxChoice *item = (wxChoice *) clientData;
424 if (item)
425 {
426 if (item->InSetValue())
427 return;
428
429 int n = item->GetWidgets().Index(w);
430 if (n != wxNOT_FOUND)
431 {
432 wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, item->GetId());
433 event.SetEventObject(item);
434 event.SetInt(n);
435 event.SetString( item->GetStrings().Item(n)->GetData() );
436 if ( item->HasClientObjectData() )
437 event.SetClientObject( item->GetClientObject(n) );
438 else if ( item->HasClientUntypedData() )
439 event.SetClientData( item->GetClientData(n) );
440 item->ProcessCommand (event);
441 }
442 }
443}
444
445void wxChoice::ChangeFont(bool keepOriginalSize)
446{
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?
450 if (m_mainWidget && m_font.Ok())
451 {
452 Display* dpy = XtDisplay((Widget) m_mainWidget);
453 int width, height, width1, height1;
454 GetSize(& width, & height);
455
456 WXString fontTag = wxFont::GetFontTag();
457
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);
464
465 for( unsigned int i = 0; i < m_noStrings; ++i )
466 XtVaSetValues( (Widget)m_widgetArray[i],
467 fontTag, m_font.GetFontTypeC(dpy),
468 NULL );
469
470 GetSize(& width1, & height1);
471 if (keepOriginalSize && (width != width1 || height != height1))
472 {
473 SetSize(wxDefaultCoord, wxDefaultCoord, width, height);
474 }
475 }
476}
477
478void wxChoice::ChangeBackgroundColour()
479{
480 wxDoChangeBackgroundColour(m_formWidget, m_backgroundColour);
481 wxDoChangeBackgroundColour(m_buttonWidget, m_backgroundColour);
482 wxDoChangeBackgroundColour(m_menuWidget, m_backgroundColour);
483 unsigned int i;
484 for (i = 0; i < m_noStrings; i++)
485 wxDoChangeBackgroundColour(m_widgetArray[i], m_backgroundColour);
486}
487
488void wxChoice::ChangeForegroundColour()
489{
490 wxDoChangeForegroundColour(m_formWidget, m_foregroundColour);
491 wxDoChangeForegroundColour(m_buttonWidget, m_foregroundColour);
492 wxDoChangeForegroundColour(m_menuWidget, m_foregroundColour);
493 unsigned int i;
494 for (i = 0; i < m_noStrings; i++)
495 wxDoChangeForegroundColour(m_widgetArray[i], m_foregroundColour);
496}
497
498unsigned int wxChoice::GetCount() const
499{
500 return m_noStrings;
501}
502
503void wxChoice::SetString(unsigned int WXUNUSED(n), const wxString& WXUNUSED(s))
504{
505 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
506}
507
508wxSize wxChoice::GetItemsSize() const
509{
510 int x, y, mx = 0, my = 0;
511
512 // get my
513 GetTextExtent( "|", &x, &my );
514
515 wxStringList::compatibility_iterator curr = m_stringList.GetFirst();
516 while( curr )
517 {
518 GetTextExtent( curr->GetData(), &x, &y );
519 mx = wxMax( mx, x );
520 my = wxMax( my, y );
521 curr = curr->GetNext();
522 }
523
524 return wxSize( mx, my );
525}
526
527wxSize wxChoice::DoGetBestSize() const
528{
529 wxSize items = GetItemsSize();
530 // FIXME arbitrary constants
531 return wxSize( ( items.x ? items.x + WIDTH_OVERHEAD : 120 ),
532 items.y + HEIGHT_OVERHEAD );
533}
534
535#endif // wxUSE_CHOICE