1///////////////////////////////////////////////////////////////////////////// 2// Name: src/motif/combobox.cpp 3// Purpose: wxComboBox class 4// Author: Julian Smart 5// Modified by: 6// Created: 17/09/98 7// RCS-ID: $Id: combobox.cpp 39694 2006-06-13 11:30:40Z ABX $ 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_COMBOBOX 16 17#include "wx/combobox.h" 18 19#ifndef WX_PRECOMP 20 #include "wx/arrstr.h" 21#endif 22 23#ifdef __VMS__ 24#pragma message disable nosimpint 25#endif 26#include <Xm/Xm.h> 27#ifdef __VMS__ 28#pragma message enable nosimpint 29#endif 30 31// use the old, GPL'd combobox 32#if (XmVersion < 2000) 33 34#include "xmcombo/xmcombo.h" 35 36#include "wx/motif/private.h" 37 38void wxComboBoxCallback (Widget w, XtPointer clientData, 39 XmComboBoxSelectionCallbackStruct * cbs); 40 41IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl) 42 43bool wxComboBox::Create(wxWindow *parent, wxWindowID id, 44 const wxString& value, 45 const wxPoint& pos, 46 const wxSize& size, 47 int n, const wxString choices[], 48 long style, 49 const wxValidator& validator, 50 const wxString& name) 51{ 52 if( !CreateControl( parent, id, pos, size, style, validator, name ) ) 53 return false; 54 55 m_noStrings = n; 56 57 Widget parentWidget = (Widget) parent->GetClientWidget(); 58 59 Widget buttonWidget = XtVaCreateManagedWidget(name.c_str(), 60 xmComboBoxWidgetClass, parentWidget, 61 XmNmarginHeight, 0, 62 XmNmarginWidth, 0, 63 XmNshowLabel, False, 64 XmNeditable, ((style & wxCB_READONLY) != wxCB_READONLY), 65 XmNsorted, ((style & wxCB_SORT) == wxCB_SORT), 66 XmNstaticList, ((style & wxCB_SIMPLE) == wxCB_SIMPLE), 67 NULL); 68 69 int i; 70 for (i = 0; i < n; i++) 71 { 72 wxXmString str( choices[i] ); 73 XmComboBoxAddItem(buttonWidget, str(), 0); 74 m_stringList.Add(choices[i]); 75 } 76 77 m_mainWidget = (Widget) buttonWidget; 78 79 XtManageChild (buttonWidget); 80 81 SetValue(value); 82 83 ChangeFont(false); 84 85 XtAddCallback (buttonWidget, XmNselectionCallback, (XtCallbackProc) wxComboBoxCallback, 86 (XtPointer) this); 87 XtAddCallback (buttonWidget, XmNvalueChangedCallback, (XtCallbackProc) wxComboBoxCallback, 88 (XtPointer) this); 89 90 AttachWidget (parent, m_mainWidget, (WXWidget) NULL, pos.x, pos.y, size.x, size.y); 91 92 ChangeBackgroundColour(); 93 94 return true; 95} 96 97bool wxComboBox::Create(wxWindow *parent, wxWindowID id, 98 const wxString& value, 99 const wxPoint& pos, 100 const wxSize& size, 101 const wxArrayString& choices, 102 long style, 103 const wxValidator& validator, 104 const wxString& name) 105{ 106 wxCArrayString chs(choices); 107 return Create(parent, id, value, pos, size, chs.GetCount(), 108 chs.GetStrings(), style, validator, name); 109} 110 111wxComboBox::~wxComboBox() 112{ 113 DetachWidget((Widget) m_mainWidget); // Removes event handlers 114 XtDestroyWidget((Widget) m_mainWidget); 115 m_mainWidget = (WXWidget) 0; 116 if ( HasClientObjectData() ) 117 m_clientDataDict.DestroyData(); 118} 119 120void wxComboBox::DoSetSize(int x, int y, 121 int width, int WXUNUSED(height), 122 int sizeFlags) 123{ 124 // Necessary so it doesn't call wxChoice::SetSize 125 wxWindow::DoSetSize(x, y, width, DoGetBestSize().y, sizeFlags); 126} 127 128wxString wxComboBox::GetValue() const 129{ 130 char *s = XmComboBoxGetString ((Widget) m_mainWidget); 131 if (s) 132 { 133 wxString str(s); 134 XtFree (s); 135 return str; 136 } 137 else 138 return wxEmptyString; 139} 140 141void wxComboBox::SetValue(const wxString& value) 142{ 143 m_inSetValue = true; 144 if( !value.empty() ) 145 XmComboBoxSetString( (Widget)m_mainWidget, 146 wxConstCast(value.c_str(), char) ); 147 m_inSetValue = false; 148} 149 150void wxComboBox::SetString(unsigned int WXUNUSED(n), const wxString& WXUNUSED(s)) 151{ 152 wxFAIL_MSG( wxT("wxComboBox::SetString only implemented for Motif 2.0") ); 153} 154 155int wxComboBox::DoAppend(const wxString& item) 156{ 157 wxXmString str( item.c_str() ); 158 XmComboBoxAddItem((Widget) m_mainWidget, str(), 0); 159 m_stringList.Add(item); 160 m_noStrings ++; 161 162 return GetCount() - 1; 163} 164 165int wxComboBox::DoInsert(const wxString& item, unsigned int pos) 166{ 167 wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list")); 168 wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index")); 169 170 if (pos == GetCount()) 171 return DoAppend(item); 172 173 wxXmString str( item.c_str() ); 174 XmComboBoxAddItem((Widget) m_mainWidget, str(), pos+1); 175 wxChar* copy = wxStrcpy(new wxChar[item.length() + 1], item.c_str()); 176 m_stringList.Insert(pos, copy); 177 m_noStrings ++; 178 179 return pos; 180} 181 182void wxComboBox::Delete(unsigned int n) 183{ 184 XmComboBoxDeletePos((Widget) m_mainWidget, n+1); 185 wxStringList::Node *node = m_stringList.Item(n); 186 if (node) 187 { 188 delete[] node->GetData(); 189 delete node; 190 } 191 m_clientDataDict.Delete(n, HasClientObjectData()); 192 m_noStrings--; 193} 194 195void wxComboBox::Clear() 196{ 197 XmComboBoxDeleteAllItems((Widget) m_mainWidget); 198 m_stringList.Clear(); 199 200 if ( HasClientObjectData() ) 201 m_clientDataDict.DestroyData(); 202 m_noStrings = 0; 203} 204 205void wxComboBox::SetSelection (int n) 206{ 207 XmComboBoxSelectPos((Widget) m_mainWidget, n+1, False); 208} 209 210int wxComboBox::GetSelection (void) const 211{ 212 int sel = XmComboBoxGetSelectedPos((Widget) m_mainWidget); 213 if (sel == 0) 214 return -1; 215 else 216 return sel - 1; 217} 218 219wxString wxComboBox::GetString(unsigned int n) const 220{ 221 wxStringList::Node *node = m_stringList.Item(n); 222 if (node) 223 return wxString(node->GetData ()); 224 else 225 return wxEmptyString; 226} 227 228int wxComboBox::FindString(const wxString& s, bool WXUNUSED(bCase)) const 229{ 230 // FIXME: back to base class for not supported value of bCase 231 232 int *pos_list = NULL; 233 int count = 0; 234 wxXmString text( s ); 235 bool found = (XmComboBoxGetMatchPos((Widget) m_mainWidget, 236 text(), &pos_list, &count) != 0); 237 238 if (found && count > 0) 239 { 240 int pos = pos_list[0] - 1; 241 free(pos_list); 242 return pos; 243 } 244 245 return wxNOT_FOUND; 246} 247 248// Clipboard operations 249void wxComboBox::Copy() 250{ 251 XmComboBoxCopy((Widget) m_mainWidget, CurrentTime); 252} 253 254void wxComboBox::Cut() 255{ 256 XmComboBoxCut((Widget) m_mainWidget, CurrentTime); 257} 258 259void wxComboBox::Paste() 260{ 261 XmComboBoxPaste((Widget) m_mainWidget); 262} 263 264void wxComboBox::SetEditable(bool WXUNUSED(editable)) 265{ 266 // TODO 267} 268 269void wxComboBox::SetInsertionPoint(long pos) 270{ 271 XmComboBoxSetInsertionPosition ((Widget) m_mainWidget, (XmTextPosition) pos); 272} 273 274void wxComboBox::SetInsertionPointEnd() 275{ 276 XmTextPosition pos = XmComboBoxGetLastPosition ((Widget) m_mainWidget); 277 XmComboBoxSetInsertionPosition ((Widget) m_mainWidget, (XmTextPosition) (pos + 1)); 278} 279 280long wxComboBox::GetInsertionPoint() const 281{ 282 return (long) XmComboBoxGetInsertionPosition ((Widget) m_mainWidget); 283} 284 285wxTextPos wxComboBox::GetLastPosition() const 286{ 287 return (wxTextPos) XmComboBoxGetLastPosition ((Widget) m_mainWidget); 288} 289 290void wxComboBox::Replace(long from, long to, const wxString& value) 291{ 292 XmComboBoxReplace ((Widget) m_mainWidget, (XmTextPosition) from, 293 (XmTextPosition) to, 294 wxConstCast(value.c_str(), char)); 295} 296 297void wxComboBox::Remove(long from, long to) 298{ 299 XmComboBoxSetSelection ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to, 300 (Time) 0); 301 XmComboBoxRemove ((Widget) m_mainWidget); 302} 303 304void wxComboBox::SetSelection(long from, long to) 305{ 306 XmComboBoxSetSelection ((Widget) m_mainWidget, (XmTextPosition) from, (XmTextPosition) to, 307 (Time) 0); 308} 309 310void wxComboBoxCallback (Widget WXUNUSED(w), XtPointer clientData, 311 XmComboBoxSelectionCallbackStruct * cbs) 312{ 313 wxComboBox *item = (wxComboBox *) clientData; 314 315 switch (cbs->reason) 316 { 317 case XmCR_SINGLE_SELECT: 318 case XmCR_BROWSE_SELECT: 319 { 320 wxCommandEvent event (wxEVT_COMMAND_COMBOBOX_SELECTED, 321 item->GetId()); 322 event.SetInt(cbs->index - 1); 323 event.SetString( item->GetString ( event.GetInt() ) ); 324 if ( item->HasClientObjectData() ) 325 event.SetClientObject( item->GetClientObject(cbs->index - 1) ); 326 else if ( item->HasClientUntypedData() ) 327 event.SetClientData( item->GetClientData(cbs->index - 1) ); 328 event.SetExtraLong(true); 329 event.SetEventObject(item); 330 item->ProcessCommand (event); 331 break; 332 } 333 case XmCR_VALUE_CHANGED: 334 { 335 wxCommandEvent event (wxEVT_COMMAND_TEXT_UPDATED, item->GetId()); 336 event.SetInt(-1); 337 event.SetString( item->GetValue() ); 338 event.SetExtraLong(true); 339 event.SetEventObject(item); 340 item->ProcessCommand (event); 341 break; 342 } 343 default: 344 break; 345 } 346} 347 348void wxComboBox::ChangeFont(bool keepOriginalSize) 349{ 350 // Don't use the base class wxChoice's ChangeFont 351 wxWindow::ChangeFont(keepOriginalSize); 352} 353 354void wxComboBox::ChangeBackgroundColour() 355{ 356 wxWindow::ChangeBackgroundColour(); 357} 358 359void wxComboBox::ChangeForegroundColour() 360{ 361 wxWindow::ChangeForegroundColour(); 362} 363 364wxSize wxComboBox::DoGetBestSize() const 365{ 366 if( (GetWindowStyle() & wxCB_DROPDOWN) == wxCB_DROPDOWN || 367 (GetWindowStyle() & wxCB_READONLY) == wxCB_READONLY ) 368 { 369 wxSize items = GetItemsSize(); 370 // FIXME arbitrary constants 371 return wxSize( ( items.x ? items.x + 50 : 120 ), 372 items.y + 10 ); 373 } 374 else 375 return wxWindow::DoGetBestSize(); 376} 377 378#endif // XmVersion < 2000 379 380#endif // wxUSE_COMBOBOX 381