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