]> git.saurik.com Git - wxWidgets.git/blob - src/motif/choice.cpp
added Add/InsertTool() (patch 672032)
[wxWidgets.git] / src / motif / choice.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #ifdef __GNUG__
13 #pragma implementation "choice.h"
14 #endif
15
16 #ifdef __VMS
17 #define XtDisplay XTDISPLAY
18 #define XtParent XTPARENT
19 #endif
20
21 #include "wx/defs.h"
22
23 #include "wx/choice.h"
24 #include "wx/utils.h"
25
26 #ifdef __VMS__
27 #pragma message disable nosimpint
28 #endif
29 #include <Xm/Xm.h>
30 #include <Xm/PushBG.h>
31 #include <Xm/PushB.h>
32 #include <Xm/RowColumn.h>
33 #ifdef __VMS__
34 #pragma message enable nosimpint
35 #endif
36
37 #include "wx/motif/private.h"
38
39 IMPLEMENT_DYNAMIC_CLASS(wxChoice, wxControl)
40
41 void wxChoiceCallback (Widget w, XtPointer clientData,
42 XtPointer ptr);
43
44 wxChoice::wxChoice()
45 {
46 Init();
47 }
48
49 void wxChoice::Init()
50 {
51 InitBase();
52
53 m_noStrings = 0;
54 m_buttonWidget = (WXWidget) 0;
55 m_menuWidget = (WXWidget) 0;
56 m_formWidget = (WXWidget) 0;
57 }
58
59 bool 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
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 NULL);
79
80 XtVaSetValues ((Widget) m_formWidget, XmNspacing, 0, NULL);
81
82 /*
83 * Create the popup menu
84 */
85 m_menuWidget = (WXWidget) XmCreatePulldownMenu ((Widget) m_formWidget,
86 "choiceMenu", NULL, 0);
87
88 if (n > 0)
89 {
90 int i;
91 for (i = 0; i < n; i++)
92 Append (choices[i]);
93 }
94
95 /*
96 * Create button
97 */
98 Arg args[10];
99 Cardinal argcnt = 0;
100
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,
106 "choiceButton",
107 args, argcnt);
108
109 m_mainWidget = m_buttonWidget;
110
111 XtManageChild ((Widget) m_buttonWidget);
112
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
119 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g.
120 // in controls sample.
121 //
122 // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget);
123 // XtUnmanageChild (optionLabel);
124 #endif
125 #endif
126
127 wxSize bestSize = GetBestSize();
128 if( size.x > 0 ) bestSize.x = size.x;
129 if( size.y > 0 ) bestSize.y = size.y;
130
131 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
132
133 ChangeFont(FALSE);
134
135 AttachWidget (parent, m_buttonWidget, m_formWidget,
136 pos.x, pos.y, bestSize.x, bestSize.y);
137
138 ChangeBackgroundColour();
139
140 return TRUE;
141 }
142
143 wxChoice::~wxChoice()
144 {
145 // For some reason destroying the menuWidget
146 // can cause crashes on some machines. It will
147 // be deleted implicitly by deleting the parent form
148 // anyway.
149 // XtDestroyWidget (menuWidget);
150
151 if (GetMainWidget())
152 {
153 DetachWidget(GetMainWidget()); // Removes event handlers
154 DetachWidget(m_formWidget);
155
156 XtDestroyWidget((Widget) m_formWidget);
157 m_formWidget = (WXWidget) 0;
158
159 // Presumably the other widgets have been deleted now, via the form
160 m_mainWidget = (WXWidget) 0;
161 m_buttonWidget = (WXWidget) 0;
162 }
163 if ( HasClientObjectData() )
164 m_clientDataDict.DestroyData();
165 }
166
167 int wxChoice::DoAppend(const wxString& item)
168 {
169 Widget w = XtVaCreateManagedWidget (wxStripMenuCodes(item),
170 #if USE_GADGETS
171 xmPushButtonGadgetClass, (Widget) m_menuWidget,
172 #else
173 xmPushButtonWidgetClass, (Widget) m_menuWidget,
174 #endif
175 NULL);
176
177 DoChangeBackgroundColour((WXWidget) w, m_backgroundColour);
178
179 if (m_font.Ok())
180 XtVaSetValues (w,
181 XmNfontList, (XmFontList) m_font.GetFontList(1.0, XtDisplay((Widget) m_formWidget)),
182 NULL);
183
184 m_widgetArray.Add(w);
185
186 char mnem = wxFindMnemonic ((char*) (const char*) item);
187 if (mnem != 0)
188 XtVaSetValues (w, XmNmnemonic, mnem, NULL);
189
190 XtAddCallback (w, XmNactivateCallback,
191 (XtCallbackProc) wxChoiceCallback,
192 (XtPointer) this);
193
194 if (m_noStrings == 0 && m_buttonWidget)
195 {
196 XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, w, NULL);
197 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
198 wxXmString text( item );
199 XtVaSetValues (label,
200 XmNlabelString, text(),
201 NULL);
202 }
203 m_stringList.Add(item);
204 m_noStrings ++;
205
206 return GetCount() - 1;
207 }
208
209 void wxChoice::Delete(int n)
210 {
211 Widget w = (Widget)m_widgetArray[n];
212 XtRemoveCallback(w, XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
213 (XtPointer)this);
214 m_stringList.DeleteNode(m_stringList.Item(n));
215 m_widgetArray.RemoveAt(size_t(n));
216 m_clientDataDict.Delete(n, HasClientObjectData());
217
218 XtDestroyWidget(w);
219 m_noStrings --;
220 }
221
222 void wxChoice::Clear()
223 {
224 m_stringList.Clear ();
225 size_t i;
226 for (i = 0; i < m_noStrings; i++)
227 {
228 XtRemoveCallback((Widget) m_widgetArray[i],
229 XmNactivateCallback, (XtCallbackProc)wxChoiceCallback,
230 (XtPointer)this);
231 XtUnmanageChild ((Widget) m_widgetArray[i]);
232 XtDestroyWidget ((Widget) m_widgetArray[i]);
233 }
234 m_widgetArray.Clear();
235 if (m_buttonWidget)
236 XtVaSetValues ((Widget) m_buttonWidget,
237 XmNmenuHistory, (Widget) NULL,
238 NULL);
239
240 if ( HasClientObjectData() )
241 m_clientDataDict.DestroyData();
242
243 m_noStrings = 0;
244 }
245
246 int wxChoice::GetSelection() const
247 {
248 XmString text;
249 char *s;
250 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
251 XtVaGetValues (label,
252 XmNlabelString, &text,
253 NULL);
254
255 if (XmStringGetLtoR (text, XmSTRING_DEFAULT_CHARSET, &s))
256 {
257 int i = 0;
258 for (wxStringListNode* node = m_stringList.GetFirst ();
259 node; node = node->GetNext ())
260 {
261 if (strcmp(node->GetData(), s) == 0)
262 {
263 XmStringFree(text) ;
264 XtFree (s);
265 return i;
266 }
267 else
268 i++;
269 } // for()
270
271 XmStringFree(text) ;
272 XtFree (s);
273 return -1;
274 }
275 XmStringFree(text) ;
276 return -1;
277 }
278
279 void wxChoice::SetSelection(int n)
280 {
281 m_inSetValue = TRUE;
282
283 wxStringListNode *node = m_stringList.Item(n);
284 if (node)
285 {
286 #if 0
287 Dimension selectionWidth, selectionHeight;
288 #endif
289 wxXmString text( node->GetData() );
290 // MBN: this seems silly, at best, and causes wxChoices to be clipped:
291 // will remove "soon"
292 #if 0
293 XtVaGetValues ((Widget) m_widgetArray[n],
294 XmNwidth, &selectionWidth,
295 XmNheight, &selectionHeight,
296 NULL);
297 #endif
298 Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget);
299 XtVaSetValues (label,
300 XmNlabelString, text(),
301 NULL);
302 #if 0
303 XtVaSetValues ((Widget) m_buttonWidget,
304 XmNwidth, selectionWidth, XmNheight, selectionHeight,
305 XmNmenuHistory, (Widget) m_widgetArray[n], NULL);
306 #endif
307 }
308 m_inSetValue = FALSE;
309 }
310
311 int wxChoice::FindString(const wxString& s) const
312 {
313 int i = 0;
314 for (wxStringListNode* node = m_stringList.GetFirst();
315 node; node = node->GetNext ())
316 {
317 if (s == node->GetData())
318 return i;
319
320 i++;
321 }
322
323 return -1;
324 }
325
326 wxString wxChoice::GetString(int n) const
327 {
328 wxStringListNode *node = m_stringList.Item(n);
329 if (node)
330 return node->GetData();
331 else
332 return wxEmptyString;
333 }
334
335 void wxChoice::SetColumns(int n)
336 {
337 if (n<1) n = 1 ;
338
339 short numColumns = n ;
340 Arg args[3];
341
342 XtSetArg(args[0], XmNnumColumns, numColumns);
343 XtSetArg(args[1], XmNpacking, XmPACK_COLUMN);
344 XtSetValues((Widget) m_menuWidget,args,2) ;
345 }
346
347 int wxChoice::GetColumns(void) const
348 {
349 short numColumns ;
350
351 XtVaGetValues((Widget) m_menuWidget,XmNnumColumns,&numColumns,NULL) ;
352 return numColumns ;
353 }
354
355 void wxChoice::SetFocus()
356 {
357 XmProcessTraversal(XtParent((Widget)m_mainWidget), XmTRAVERSE_CURRENT);
358 }
359
360 void wxChoice::DoSetSize(int x, int y, int width, int height, int sizeFlags)
361 {
362 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
363 bool managed = XtIsManaged((Widget) m_formWidget);
364
365 if (managed)
366 XtUnmanageChild ((Widget) m_formWidget);
367
368 int actualWidth = width, actualHeight = height;
369
370 if (width > -1)
371 {
372 size_t i;
373 for (i = 0; i < m_noStrings; i++)
374 XtVaSetValues ((Widget) m_widgetArray[i],
375 XmNwidth, actualWidth,
376 NULL);
377 XtVaSetValues ((Widget) m_buttonWidget, XmNwidth, actualWidth,
378 NULL);
379 }
380 if (height > -1)
381 {
382 size_t i;
383 for (i = 0; i < m_noStrings; i++)
384 XtVaSetValues ((Widget) m_widgetArray[i],
385 XmNheight, actualHeight,
386 NULL);
387 XtVaSetValues ((Widget) m_buttonWidget, XmNheight, actualHeight,
388 NULL);
389 }
390
391 if (managed)
392 XtManageChild ((Widget) m_formWidget);
393 XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
394
395 wxControl::DoSetSize (x, y, width, height, sizeFlags);
396 }
397
398 void wxChoice::Command(wxCommandEvent & event)
399 {
400 SetSelection (event.GetInt());
401 ProcessCommand (event);
402 }
403
404 void wxChoiceCallback (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr))
405 {
406 wxChoice *item = (wxChoice *) clientData;
407 if (item)
408 {
409 if (item->InSetValue())
410 return;
411
412 int n = item->GetWidgets().Index(w);
413 if (n != wxNOT_FOUND)
414 {
415 wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, item->GetId());
416 event.SetEventObject(item);
417 event.m_commandInt = n;
418 event.m_commandString = item->GetStrings().Item(n)->GetData();
419 if ( item->HasClientObjectData() )
420 event.SetClientObject( item->GetClientObject(n) );
421 else if ( item->HasClientUntypedData() )
422 event.SetClientData( item->GetClientData(n) );
423 item->ProcessCommand (event);
424 }
425 }
426 }
427
428 void wxChoice::ChangeFont(bool keepOriginalSize)
429 {
430 // Note that this causes the widget to be resized back
431 // to its original size! We therefore have to set the size
432 // back again. TODO: a better way in Motif?
433 if (m_font.Ok())
434 {
435 int width, height, width1, height1;
436 GetSize(& width, & height);
437
438 XmFontList fontList = (XmFontList) m_font.GetFontList(1.0, XtDisplay((Widget) m_mainWidget));
439 XtVaSetValues ((Widget) m_formWidget, XmNfontList, fontList, NULL);
440 XtVaSetValues ((Widget) m_buttonWidget, XmNfontList, fontList, NULL);
441
442 for( size_t i = 0; i < m_noStrings; ++i )
443 XtVaSetValues( (Widget)m_widgetArray[i],
444 XmNfontList, fontList,
445 NULL );
446
447 GetSize(& width1, & height1);
448 if (keepOriginalSize && (width != width1 || height != height1))
449 {
450 SetSize(-1, -1, width, height);
451 }
452 }
453 }
454
455 void wxChoice::ChangeBackgroundColour()
456 {
457 DoChangeBackgroundColour(m_formWidget, m_backgroundColour);
458 DoChangeBackgroundColour(m_buttonWidget, m_backgroundColour);
459 DoChangeBackgroundColour(m_menuWidget, m_backgroundColour);
460 size_t i;
461 for (i = 0; i < m_noStrings; i++)
462 DoChangeBackgroundColour(m_widgetArray[i], m_backgroundColour);
463 }
464
465 void wxChoice::ChangeForegroundColour()
466 {
467 DoChangeForegroundColour(m_formWidget, m_foregroundColour);
468 DoChangeForegroundColour(m_buttonWidget, m_foregroundColour);
469 DoChangeForegroundColour(m_menuWidget, m_foregroundColour);
470 size_t i;
471 for (i = 0; i < m_noStrings; i++)
472 DoChangeForegroundColour(m_widgetArray[i], m_foregroundColour);
473 }
474
475 int wxChoice::GetCount() const
476 {
477 return m_noStrings;
478 }
479
480 void wxChoice::DoSetItemClientData(int n, void* clientData)
481 {
482 m_clientDataDict.Set(n, (wxClientData*)clientData, FALSE);
483 }
484
485 void* wxChoice::DoGetItemClientData(int n) const
486 {
487 return (void*)m_clientDataDict.Get(n);
488 }
489
490 void wxChoice::DoSetItemClientObject(int n, wxClientData* clientData)
491 {
492 // don't delete, wxItemContainer does that for us
493 m_clientDataDict.Set(n, clientData, FALSE);
494 }
495
496 wxClientData* wxChoice::DoGetItemClientObject(int n) const
497 {
498 return m_clientDataDict.Get(n);
499 }
500
501 void wxChoice::SetString(int WXUNUSED(n), const wxString& WXUNUSED(s))
502 {
503 wxFAIL_MSG( wxT("wxChoice::SetString not implemented") );
504 }
505
506 wxSize wxChoice::GetItemsSize() const
507 {
508 int x, y, mx = 0, my = 0;
509
510 // get my
511 GetTextExtent( "|", &x, &my );
512
513 wxStringList::Node* curr = m_stringList.GetFirst();
514 while( curr )
515 {
516 GetTextExtent( curr->GetData(), &x, &y );
517 mx = wxMax( mx, x );
518 my = wxMax( my, y );
519 curr = curr->GetNext();
520 }
521
522 return wxSize( mx, my );
523 }
524
525 wxSize wxChoice::DoGetBestSize() const
526 {
527 wxSize items = GetItemsSize();
528 // FIXME arbitrary constants
529 return wxSize( ( items.x ? items.x + 50 : 120 ),
530 items.y + 15 );
531 }