1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/motif/choice.cpp 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  17 #include "wx/choice.h" 
  21     #include "wx/arrstr.h" 
  25 #pragma message disable nosimpint 
  28 #include <Xm/PushBG.h> 
  30 #include <Xm/RowColumn.h> 
  32 #pragma message enable nosimpint 
  35 #include "wx/motif/private.h" 
  37 #define WIDTH_OVERHEAD 48 
  38 #define WIDTH_OVERHEAD_SUBTRACT 40 
  39 #define HEIGHT_OVERHEAD 15 
  41 IMPLEMENT_DYNAMIC_CLASS(wxChoice
, wxControlWithItems
) 
  43 void wxChoiceCallback (Widget w
, XtPointer clientData
, 
  54     m_buttonWidget 
= (WXWidget
) 0; 
  55     m_menuWidget 
= (WXWidget
) 0; 
  56     m_formWidget 
= (WXWidget
) 0; 
  59 bool wxChoice::Create(wxWindow 
*parent
, wxWindowID id
, 
  62                       int n
, const wxString choices
[], 
  64                       const wxValidator
& validator
, 
  67     if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) ) 
  71     Widget parentWidget 
= (Widget
) parent
->GetClientWidget(); 
  73     m_formWidget 
= (WXWidget
) XtVaCreateManagedWidget(name
.c_str(), 
  74         xmRowColumnWidgetClass
, parentWidget
, 
  77         XmNpacking
, XmPACK_TIGHT
, 
  78         XmNorientation
, XmHORIZONTAL
, 
  79         XmNresizeWidth
, False
, 
  80         XmNresizeHeight
, False
, 
  83     XtVaSetValues ((Widget
) m_formWidget
, XmNspacing
, 0, NULL
); 
  86     * Create the popup menu 
  88     m_menuWidget 
= (WXWidget
) XmCreatePulldownMenu ((Widget
) m_formWidget
, 
  89                                                     wxMOTIF_STR("choiceMenu"), 
  95         for (i 
= 0; i 
< n
; i
++) 
 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"), 
 113     m_mainWidget 
= m_buttonWidget
; 
 115     XtManageChild ((Widget
) m_buttonWidget
); 
 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 
 123     // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g. 
 124     // in controls sample. 
 126     // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget); 
 127     // XtUnmanageChild (optionLabel); 
 131     wxSize bestSize 
= GetBestSize(); 
 132     if( size
.x 
> 0 ) bestSize
.x 
= size
.x
; 
 133     if( size
.y 
> 0 ) bestSize
.y 
= size
.y
; 
 135     XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
); 
 138     AttachWidget (parent
, m_buttonWidget
, m_formWidget
, 
 139                   pos
.x
, pos
.y
, bestSize
.x
, bestSize
.y
); 
 144 bool wxChoice::Create(wxWindow 
*parent
, wxWindowID id
, 
 147                       const wxArrayString
& choices
, 
 149                       const wxValidator
& validator
, 
 150                       const wxString
& name
) 
 152     wxCArrayString 
chs(choices
); 
 153     return Create(parent
, id
, pos
, size
, chs
.GetCount(), chs
.GetStrings(), 
 154                   style
, validator
, name
); 
 157 wxChoice::~wxChoice() 
 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 
 163     //  XtDestroyWidget (menuWidget); 
 167         DetachWidget(GetMainWidget()); // Removes event handlers 
 168         DetachWidget(m_formWidget
); 
 170         XtDestroyWidget((Widget
) m_formWidget
); 
 171         m_formWidget 
= (WXWidget
) 0; 
 173         // Presumably the other widgets have been deleted now, via the form 
 174         m_mainWidget 
= (WXWidget
) 0; 
 175         m_buttonWidget 
= (WXWidget
) 0; 
 179 static inline wxChar
* MYcopystring(const wxChar
* s
) 
 181     wxChar
* copy 
= new wxChar
[wxStrlen(s
) + 1]; 
 182     return wxStrcpy(copy
, s
); 
 185 // TODO auto-sorting is not supported by the code 
 186 int wxChoice::DoInsertItems(const wxArrayStringsAdapter
& items
, 
 188                             void **clientData
, wxClientDataType type
) 
 190 #ifndef XmNpositionIndex 
 191     wxCHECK_MSG( pos 
== GetCount(), -1, wxT("insert not implemented")); 
 194     const unsigned int numItems 
= items
.GetCount(); 
 195     AllocClientData(numItems
); 
 196     for( unsigned int i 
= 0; i 
< numItems
; ++i
, ++pos 
) 
 198         Widget w 
= XtVaCreateManagedWidget (GetLabelText(items
[i
]), 
 200             xmPushButtonGadgetClass
, (Widget
) m_menuWidget
, 
 202             xmPushButtonWidgetClass
, (Widget
) m_menuWidget
, 
 204 #ifdef XmNpositionIndex 
 205             XmNpositionIndex
, pos
, 
 209         wxDoChangeBackgroundColour((WXWidget
) w
, m_backgroundColour
); 
 212             wxDoChangeFont( w
, m_font 
); 
 214         m_widgetArray
.Insert(w
, pos
); 
 216         char mnem 
= wxFindMnemonic (items
[i
]); 
 218             XtVaSetValues (w
, XmNmnemonic
, mnem
, NULL
); 
 220         XtAddCallback (w
, XmNactivateCallback
, 
 221                        (XtCallbackProc
) wxChoiceCallback
, 
 224         if (m_noStrings 
== 0 && m_buttonWidget
) 
 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(), 
 233         // need to ditch wxStringList for wxArrayString 
 234         m_stringList
.Insert(pos
, MYcopystring(items
[i
])); 
 237         InsertNewItemClientData(pos
, clientData
, i
, type
); 
 243 void wxChoice::DoDeleteOneItem(unsigned int n
) 
 245     Widget w 
= (Widget
)m_widgetArray
[n
]; 
 246     XtRemoveCallback(w
, XmNactivateCallback
, (XtCallbackProc
)wxChoiceCallback
, 
 248     m_stringList
.Erase(m_stringList
.Item(n
)); 
 249     m_widgetArray
.RemoveAt(size_t(n
)); 
 250     wxChoiceBase::DoDeleteOneItem(n
); 
 256 void wxChoice::DoClear() 
 258     m_stringList
.Clear (); 
 260     for (i 
= 0; i 
< m_noStrings
; i
++) 
 262         XtRemoveCallback((Widget
) m_widgetArray
[i
], 
 263                          XmNactivateCallback
, (XtCallbackProc
)wxChoiceCallback
, 
 265         XtUnmanageChild ((Widget
) m_widgetArray
[i
]); 
 266         XtDestroyWidget ((Widget
) m_widgetArray
[i
]); 
 268     m_widgetArray
.Clear(); 
 270         XtVaSetValues ((Widget
) m_buttonWidget
, 
 271                        XmNmenuHistory
, (Widget
) NULL
, 
 274     wxChoiceBase::DoClear(); 
 279 int wxChoice::GetSelection() const 
 282     Widget label 
= XmOptionButtonGadget ((Widget
) m_buttonWidget
); 
 283     XtVaGetValues (label
, 
 284         XmNlabelString
, &text
, 
 286     wxXmString 
freeMe(text
); 
 287     wxString s 
= wxXmStringToString( text 
); 
 292         for (wxStringList::compatibility_iterator node 
= m_stringList
.GetFirst (); 
 293              node
; node 
= node
->GetNext ()) 
 295             if (wxStrcmp(node
->GetData(), s
.c_str()) == 0) 
 308 void wxChoice::SetSelection(int n
) 
 312     wxStringList::compatibility_iterator node 
= m_stringList
.Item(n
); 
 316         Dimension selectionWidth
, selectionHeight
; 
 318         wxXmString 
text( node
->GetData() ); 
 319 // MBN: this seems silly, at best, and causes wxChoices to be clipped: 
 320 //      will remove "soon" 
 322         XtVaGetValues ((Widget
) m_widgetArray
[n
], 
 323                        XmNwidth
, &selectionWidth
, 
 324                        XmNheight
, &selectionHeight
, 
 327         Widget label 
= XmOptionButtonGadget ((Widget
) m_buttonWidget
); 
 328         XtVaSetValues (label
, 
 329             XmNlabelString
, text(), 
 332         XtVaSetValues ((Widget
) m_buttonWidget
, 
 333             XmNwidth
, selectionWidth
, XmNheight
, selectionHeight
, 
 334             XmNmenuHistory
, (Widget
) m_widgetArray
[n
], NULL
); 
 337     m_inSetValue 
= false; 
 340 wxString 
wxChoice::GetString(unsigned int n
) const 
 342     wxStringList::compatibility_iterator node 
= m_stringList
.Item(n
); 
 344         return node
->GetData(); 
 346         return wxEmptyString
; 
 349 void wxChoice::SetColumns(int n
) 
 353     short numColumns 
= (short)n 
; 
 356     XtSetArg(args
[0], XmNnumColumns
, numColumns
); 
 357     XtSetArg(args
[1], XmNpacking
, XmPACK_COLUMN
); 
 358     XtSetValues((Widget
) m_menuWidget
,args
,2) ; 
 361 int wxChoice::GetColumns(void) const 
 365     XtVaGetValues((Widget
) m_menuWidget
,XmNnumColumns
,&numColumns
,NULL
) ; 
 369 void wxChoice::SetFocus() 
 371     XmProcessTraversal(XtParent((Widget
)m_mainWidget
), XmTRAVERSE_CURRENT
); 
 374 void wxChoice::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
) 
 376     XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_ANY
, NULL
); 
 377     bool managed 
= XtIsManaged((Widget
) m_formWidget
); 
 380         XtUnmanageChild ((Widget
) m_formWidget
); 
 382     int actualWidth 
= width 
- WIDTH_OVERHEAD_SUBTRACT
, 
 383         actualHeight 
= height 
- HEIGHT_OVERHEAD
; 
 388         for (i 
= 0; i 
< m_noStrings
; i
++) 
 389             XtVaSetValues ((Widget
) m_widgetArray
[i
], 
 390                            XmNwidth
, actualWidth
, 
 392         XtVaSetValues ((Widget
) m_buttonWidget
, XmNwidth
, actualWidth
, 
 399         for (i 
= 0; i 
< m_noStrings
; i
++) 
 400             XtVaSetValues ((Widget
) m_widgetArray
[i
], 
 401                            XmNheight
, actualHeight
, 
 404         XtVaSetValues ((Widget
) m_buttonWidget
, XmNheight
, actualHeight
, 
 409         XtManageChild ((Widget
) m_formWidget
); 
 410     XtVaSetValues((Widget
) m_formWidget
, XmNresizePolicy
, XmRESIZE_NONE
, NULL
); 
 412     wxControl::DoSetSize (x
, y
, width
, height
, sizeFlags
); 
 415 void wxChoice::Command(wxCommandEvent 
& event
) 
 417     SetSelection (event
.GetInt()); 
 418     ProcessCommand (event
); 
 421 void wxChoiceCallback (Widget w
, XtPointer clientData
, XtPointer 
WXUNUSED(ptr
)) 
 423     wxChoice 
*item 
= (wxChoice 
*) clientData
; 
 426         if (item
->InSetValue()) 
 429         int n 
= item
->GetWidgets().Index(w
); 
 430         if (n 
!= wxNOT_FOUND
) 
 432             wxCommandEvent 
event(wxEVT_COMMAND_CHOICE_SELECTED
, item
->GetId()); 
 433             event
.SetEventObject(item
); 
 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
); 
 445 void wxChoice::ChangeFont(bool keepOriginalSize
) 
 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()) 
 452         Display
* dpy 
= XtDisplay((Widget
) m_mainWidget
); 
 453         int width
, height
, width1
, height1
; 
 454         GetSize(& width
, & height
); 
 456         WXString fontTag 
= wxFont::GetFontTag(); 
 458         XtVaSetValues ((Widget
) m_formWidget
, 
 459                        fontTag
, m_font
.GetFontTypeC(dpy
), 
 461         XtVaSetValues ((Widget
) m_buttonWidget
, 
 462                        fontTag
, m_font
.GetFontTypeC(dpy
), 
 465         for( unsigned int i 
= 0; i 
< m_noStrings
; ++i 
) 
 466             XtVaSetValues( (Widget
)m_widgetArray
[i
], 
 467                            fontTag
, m_font
.GetFontTypeC(dpy
), 
 470         GetSize(& width1
, & height1
); 
 471         if (keepOriginalSize 
&& (width 
!= width1 
|| height 
!= height1
)) 
 473             SetSize(wxDefaultCoord
, wxDefaultCoord
, width
, height
); 
 478 void wxChoice::ChangeBackgroundColour() 
 480     wxDoChangeBackgroundColour(m_formWidget
, m_backgroundColour
); 
 481     wxDoChangeBackgroundColour(m_buttonWidget
, m_backgroundColour
); 
 482     wxDoChangeBackgroundColour(m_menuWidget
, m_backgroundColour
); 
 484     for (i 
= 0; i 
< m_noStrings
; i
++) 
 485         wxDoChangeBackgroundColour(m_widgetArray
[i
], m_backgroundColour
); 
 488 void wxChoice::ChangeForegroundColour() 
 490     wxDoChangeForegroundColour(m_formWidget
, m_foregroundColour
); 
 491     wxDoChangeForegroundColour(m_buttonWidget
, m_foregroundColour
); 
 492     wxDoChangeForegroundColour(m_menuWidget
, m_foregroundColour
); 
 494     for (i 
= 0; i 
< m_noStrings
; i
++) 
 495         wxDoChangeForegroundColour(m_widgetArray
[i
], m_foregroundColour
); 
 498 unsigned int wxChoice::GetCount() const 
 503 void wxChoice::SetString(unsigned int WXUNUSED(n
), const wxString
& WXUNUSED(s
)) 
 505     wxFAIL_MSG( wxT("wxChoice::SetString not implemented") ); 
 508 wxSize 
wxChoice::GetItemsSize() const 
 510     int x
, y
, mx 
= 0, my 
= 0; 
 513     GetTextExtent( "|", &x
, &my 
); 
 515     wxStringList::compatibility_iterator curr 
= m_stringList
.GetFirst(); 
 518         GetTextExtent( curr
->GetData(), &x
, &y 
); 
 521         curr 
= curr
->GetNext(); 
 524     return wxSize( mx
, my 
); 
 527 wxSize 
wxChoice::DoGetBestSize() const 
 529     wxSize items 
= GetItemsSize(); 
 530     // FIXME arbitrary constants 
 531     return wxSize( ( items
.x 
? items
.x 
+ WIDTH_OVERHEAD 
: 120 ), 
 532                      items
.y 
+ HEIGHT_OVERHEAD 
); 
 535 #endif // wxUSE_CHOICE