///////////////////////////////////////////////////////////////////////////// // Name: src/motif/choice.cpp // Purpose: wxChoice // Author: Julian Smart // Modified by: // Created: 17/09/98 // Copyright: (c) Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #if wxUSE_CHOICE #include "wx/choice.h" #ifndef WX_PRECOMP #include "wx/utils.h" #include "wx/arrstr.h" #endif #ifdef __VMS__ #pragma message disable nosimpint #endif #include #include #include #include #ifdef __VMS__ #pragma message enable nosimpint #endif #include "wx/motif/private.h" #define WIDTH_OVERHEAD 48 #define WIDTH_OVERHEAD_SUBTRACT 40 #define HEIGHT_OVERHEAD 15 void wxChoiceCallback (Widget w, XtPointer clientData, XtPointer ptr); wxChoice::wxChoice() { Init(); } void wxChoice::Init() { m_buttonWidget = (WXWidget) 0; m_menuWidget = (WXWidget) 0; m_formWidget = (WXWidget) 0; } bool wxChoice::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, int n, const wxString choices[], long style, const wxValidator& validator, const wxString& name) { if ( !CreateControl(parent, id, pos, size, style, validator, name) ) return false; PreCreation(); Widget parentWidget = (Widget) parent->GetClientWidget(); m_formWidget = (WXWidget) XtVaCreateManagedWidget(name.c_str(), xmRowColumnWidgetClass, parentWidget, XmNmarginHeight, 0, XmNmarginWidth, 0, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNresizeWidth, False, XmNresizeHeight, False, NULL); XtVaSetValues ((Widget) m_formWidget, XmNspacing, 0, NULL); /* * Create the popup menu */ m_menuWidget = (WXWidget) XmCreatePulldownMenu ((Widget) m_formWidget, wxMOTIF_STR("choiceMenu"), NULL, 0); if (n > 0) { int i; for (i = 0; i < n; i++) Append (choices[i]); } /* * Create button */ Arg args[10]; Cardinal argcnt = 0; XtSetArg (args[argcnt], XmNsubMenuId, (Widget) m_menuWidget); ++argcnt; XtSetArg (args[argcnt], XmNmarginWidth, 0); ++argcnt; XtSetArg (args[argcnt], XmNmarginHeight, 0); ++argcnt; XtSetArg (args[argcnt], XmNpacking, XmPACK_TIGHT); ++argcnt; m_buttonWidget = (WXWidget) XmCreateOptionMenu ((Widget) m_formWidget, wxMOTIF_STR("choiceButton"), args, argcnt); m_mainWidget = m_buttonWidget; XtManageChild ((Widget) m_buttonWidget); // New code from Roland Haenel (roland_haenel@ac.cybercity.de) // Some time ago, I reported a problem with wxChoice-items under // Linux and Motif 2.0 (they caused sporadic GPFs). Now it seems // that I have found the code responsible for this behaviour. #if XmVersion >= 1002 #if XmVersion < 2000 // JACS, 24/1/99: this seems to cause a malloc crash later on, e.g. // in controls sample. // // Widget optionLabel = XmOptionLabelGadget ((Widget) m_buttonWidget); // XtUnmanageChild (optionLabel); #endif #endif wxSize bestSize = GetBestSize(); if( size.x > 0 ) bestSize.x = size.x; if( size.y > 0 ) bestSize.y = size.y; XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL); PostCreation(); AttachWidget (parent, m_buttonWidget, m_formWidget, pos.x, pos.y, bestSize.x, bestSize.y); return true; } bool wxChoice::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, const wxArrayString& choices, long style, const wxValidator& validator, const wxString& name) { wxCArrayString chs(choices); return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(), style, validator, name); } wxChoice::~wxChoice() { // For some reason destroying the menuWidget // can cause crashes on some machines. It will // be deleted implicitly by deleting the parent form // anyway. // XtDestroyWidget (menuWidget); if (GetMainWidget()) { DetachWidget(GetMainWidget()); // Removes event handlers DetachWidget(m_formWidget); XtDestroyWidget((Widget) m_formWidget); m_formWidget = (WXWidget) 0; // Presumably the other widgets have been deleted now, via the form m_mainWidget = (WXWidget) 0; m_buttonWidget = (WXWidget) 0; } } static inline wxChar* MYcopystring(const wxChar* s) { wxChar* copy = new wxChar[wxStrlen(s) + 1]; return wxStrcpy(copy, s); } // TODO auto-sorting is not supported by the code int wxChoice::DoInsertItems(const wxArrayStringsAdapter& items, unsigned int pos, void **clientData, wxClientDataType type) { #ifndef XmNpositionIndex wxCHECK_MSG( pos == GetCount(), -1, wxT("insert not implemented")); #endif const unsigned int numItems = items.GetCount(); AllocClientData(numItems); for( unsigned int i = 0; i < numItems; ++i, ++pos ) { Widget w = XtVaCreateManagedWidget (GetLabelText(items[i]), #if wxUSE_GADGETS xmPushButtonGadgetClass, (Widget) m_menuWidget, #else xmPushButtonWidgetClass, (Widget) m_menuWidget, #endif #ifdef XmNpositionIndex XmNpositionIndex, pos, #endif NULL); wxDoChangeBackgroundColour((WXWidget) w, m_backgroundColour); if( m_font.IsOk() ) wxDoChangeFont( w, m_font ); m_widgetArray.Insert(w, pos); char mnem = wxFindMnemonic (items[i]); if (mnem != 0) XtVaSetValues (w, XmNmnemonic, mnem, NULL); XtAddCallback (w, XmNactivateCallback, (XtCallbackProc) wxChoiceCallback, (XtPointer) this); if (m_stringArray.GetCount() == 0 && m_buttonWidget) { XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, w, NULL); Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget); wxXmString text( items[i] ); XtVaSetValues (label, XmNlabelString, text(), NULL); } m_stringArray.Insert(items[i], pos); InsertNewItemClientData(pos, clientData, i, type); } return pos - 1; } void wxChoice::DoDeleteOneItem(unsigned int n) { Widget w = (Widget)m_widgetArray[n]; XtRemoveCallback(w, XmNactivateCallback, (XtCallbackProc)wxChoiceCallback, (XtPointer)this); m_stringArray.RemoveAt(size_t(n)); m_widgetArray.RemoveAt(size_t(n)); wxChoiceBase::DoDeleteOneItem(n); XtDestroyWidget(w); } void wxChoice::DoClear() { m_stringArray.Clear(); unsigned int i; for (i = 0; i < m_stringArray.GetCount(); i++) { XtRemoveCallback((Widget) m_widgetArray[i], XmNactivateCallback, (XtCallbackProc)wxChoiceCallback, (XtPointer)this); XtUnmanageChild ((Widget) m_widgetArray[i]); XtDestroyWidget ((Widget) m_widgetArray[i]); } m_widgetArray.Clear(); if (m_buttonWidget) XtVaSetValues ((Widget) m_buttonWidget, XmNmenuHistory, (Widget) NULL, NULL); wxChoiceBase::DoClear(); } int wxChoice::GetSelection() const { XmString text; Widget label = XmOptionButtonGadget ((Widget) m_buttonWidget); XtVaGetValues (label, XmNlabelString, &text, NULL); wxXmString freeMe(text); wxString s = wxXmStringToString( text ); if (!s.empty()) { for (size_t i=0; i -1) { unsigned int i; for (i = 0; i < m_stringArray.GetCount(); i++) XtVaSetValues ((Widget) m_widgetArray[i], XmNwidth, actualWidth, NULL); XtVaSetValues ((Widget) m_buttonWidget, XmNwidth, actualWidth, NULL); } if (height > -1) { #if 0 unsigned int i; for (i = 0; i < m_stringArray.GetCount(); i++) XtVaSetValues ((Widget) m_widgetArray[i], XmNheight, actualHeight, NULL); #endif XtVaSetValues ((Widget) m_buttonWidget, XmNheight, actualHeight, NULL); } if (managed) XtManageChild ((Widget) m_formWidget); XtVaSetValues((Widget) m_formWidget, XmNresizePolicy, XmRESIZE_NONE, NULL); wxControl::DoSetSize (x, y, width, height, sizeFlags); } void wxChoice::Command(wxCommandEvent & event) { SetSelection (event.GetInt()); ProcessCommand (event); } void wxChoiceCallback (Widget w, XtPointer clientData, XtPointer WXUNUSED(ptr)) { wxChoice *item = (wxChoice *) clientData; if (item) { if (item->InSetValue()) return; int n = item->GetWidgets().Index(w); if (n != wxNOT_FOUND) { wxCommandEvent event(wxEVT_CHOICE, item->GetId()); event.SetEventObject(item); event.SetInt(n); event.SetString( item->GetStrings().Item(n) ); if ( item->HasClientObjectData() ) event.SetClientObject( item->GetClientObject(n) ); else if ( item->HasClientUntypedData() ) event.SetClientData( item->GetClientData(n) ); item->ProcessCommand (event); } } } void wxChoice::ChangeFont(bool keepOriginalSize) { // Note that this causes the widget to be resized back // to its original size! We therefore have to set the size // back again. TODO: a better way in Motif? if (m_mainWidget && m_font.IsOk()) { Display* dpy = XtDisplay((Widget) m_mainWidget); int width, height, width1, height1; GetSize(& width, & height); WXString fontTag = wxFont::GetFontTag(); XtVaSetValues ((Widget) m_formWidget, fontTag, m_font.GetFontTypeC(dpy), NULL); XtVaSetValues ((Widget) m_buttonWidget, fontTag, m_font.GetFontTypeC(dpy), NULL); for( unsigned int i = 0; i < m_stringArray.GetCount(); ++i ) XtVaSetValues( (Widget)m_widgetArray[i], fontTag, m_font.GetFontTypeC(dpy), NULL ); GetSize(& width1, & height1); if (keepOriginalSize && (width != width1 || height != height1)) { SetSize(wxDefaultCoord, wxDefaultCoord, width, height); } } } void wxChoice::ChangeBackgroundColour() { wxDoChangeBackgroundColour(m_formWidget, m_backgroundColour); wxDoChangeBackgroundColour(m_buttonWidget, m_backgroundColour); wxDoChangeBackgroundColour(m_menuWidget, m_backgroundColour); unsigned int i; for (i = 0; i < m_stringArray.GetCount(); i++) wxDoChangeBackgroundColour(m_widgetArray[i], m_backgroundColour); } void wxChoice::ChangeForegroundColour() { wxDoChangeForegroundColour(m_formWidget, m_foregroundColour); wxDoChangeForegroundColour(m_buttonWidget, m_foregroundColour); wxDoChangeForegroundColour(m_menuWidget, m_foregroundColour); unsigned int i; for (i = 0; i < m_stringArray.GetCount(); i++) wxDoChangeForegroundColour(m_widgetArray[i], m_foregroundColour); } unsigned int wxChoice::GetCount() const { return m_stringArray.GetCount(); } void wxChoice::SetString(unsigned int WXUNUSED(n), const wxString& WXUNUSED(s)) { wxFAIL_MSG( wxT("wxChoice::SetString not implemented") ); } wxSize wxChoice::GetItemsSize() const { int x, y, mx = 0, my = 0; // get my GetTextExtent( "|", &x, &my ); for (size_t i=0; i