1///////////////////////////////////////////////////////////////////////////// 2// Name: src/motif/combobox_native.cpp 3// Purpose: wxComboBox class 4// Author: Julian Smart, Ian Brown 5// Modified by: 6// Created: 01/02/03 7// RCS-ID: $Id: combobox_native.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 new, shiny combobox for Motif 2.x 32#if (XmVersion >= 2000) 33 34#ifdef __VMS__ 35#pragma message disable nosimpint 36#endif 37#include <Xm/ComboBox.h> 38#include <Xm/Text.h> 39#include <Xm/List.h> 40#ifdef __VMS__ 41#pragma message enable nosimpint 42#endif 43 44#include "wx/motif/private.h" 45 46// utility 47static Widget GetXmList( const wxComboBox* cb ) 48{ 49 Widget ret; 50 XtVaGetValues( (Widget)cb->GetMainWidget(), 51 XmNlist, &ret, 52 NULL ); 53 54 return ret; 55} 56 57static Widget GetXmText( const wxComboBox* cb ) 58{ 59 Widget ret; 60 XtVaGetValues( (Widget)cb->GetMainWidget(), 61 XmNtextField, &ret, 62 NULL ); 63 64 return ret; 65} 66 67void wxComboBoxCallback (Widget w, XtPointer clientData, 68 XmComboBoxCallbackStruct * cbs); 69 70IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl) 71 72bool wxComboBox::Create(wxWindow *parent, wxWindowID id, 73 const wxString& value, 74 const wxPoint& pos, 75 const wxSize& size, 76 int n, const wxString choices[], 77 long style, 78 const wxValidator& validator, 79 const wxString& name) 80{ 81 if( !CreateControl( parent, id, pos, size, style, validator, name ) ) 82 return false; 83 84 Widget parentWidget = (Widget) parent->GetClientWidget(); 85 86 int cb_type = ( style & wxCB_SIMPLE ) ? XmCOMBO_BOX : 87 ( style & wxCB_READONLY ) ? XmDROP_DOWN_LIST : 88 ( style & wxCB_DROPDOWN ) ? XmDROP_DOWN_COMBO_BOX : 89 // default to wxCB_DROPDOWN 90 XmDROP_DOWN_COMBO_BOX; 91 if( cb_type == XmDROP_DOWN_COMBO_BOX ) 92 SetWindowStyle( style | wxCB_DROPDOWN ); 93 94 Widget buttonWidget= XtVaCreateManagedWidget(name.c_str(), 95 xmComboBoxWidgetClass, parentWidget, 96 XmNcomboBoxType, cb_type, 97 NULL); 98 99 m_mainWidget = (Widget) buttonWidget; 100 101 int i; 102 for ( i = 0; i < n; ++i) 103 Append( choices[i] ); 104 105 XtManageChild (buttonWidget); 106 107 SetValue(value); 108 109 ChangeFont(false); 110 111 XtAddCallback (buttonWidget, XmNselectionCallback, 112 (XtCallbackProc) wxComboBoxCallback, 113 (XtPointer) this); 114 XtAddCallback (GetXmText(this), XmNvalueChangedCallback, 115 (XtCallbackProc) wxComboBoxCallback, 116 (XtPointer) this); 117 118 wxSize best = GetBestSize(); 119 if( size.x != wxDefaultCoord ) best.x = size.x; 120 if( size.y != wxDefaultCoord ) best.y = size.y; 121 122 AttachWidget (parent, m_mainWidget, (WXWidget) NULL, 123 pos.x, pos.y, best.x, best.y); 124 125 ChangeBackgroundColour(); 126 127 return true; 128} 129 130bool wxComboBox::Create(wxWindow *parent, wxWindowID id, 131 const wxString& value, 132 const wxPoint& pos, 133 const wxSize& size, 134 const wxArrayString& choices, 135 long style, 136 const wxValidator& validator, 137 const wxString& name) 138{ 139 wxCArrayString chs(choices); 140 return Create(parent, id, value, pos, size, chs.GetCount(), 141 chs.GetStrings(), style, validator, name); 142} 143 144void wxComboBox::AdjustDropDownListSize() 145{ 146 int newListCount = -1, itemCount = GetCount(); 147 const int MAX = 12; 148 149 if( !itemCount ) 150 newListCount = 1; 151 else if( itemCount < MAX ) 152 newListCount = itemCount; 153 else 154 newListCount = MAX; 155 156 XtVaSetValues( GetXmList(this), 157 XmNvisibleItemCount, newListCount, 158 NULL ); 159} 160 161wxComboBox::~wxComboBox() 162{ 163 DetachWidget((Widget) m_mainWidget); // Removes event handlers 164 XtDestroyWidget((Widget) m_mainWidget); 165 m_mainWidget = (WXWidget) 0; 166 if ( HasClientObjectData() ) 167 m_clientDataDict.DestroyData(); 168} 169 170void wxComboBox::DoSetSize(int x, int y, int width, int WXUNUSED(height), int sizeFlags) 171{ 172 // Necessary so it doesn't call wxChoice::SetSize 173 wxWindow::DoSetSize(x, y, width, DoGetBestSize().y, sizeFlags); 174} 175 176wxString wxComboBox::GetValue() const 177{ 178 char* s = XmTextGetString (GetXmText (this)); 179 wxString str(s); 180 if (s) 181 XtFree (s); 182 return str; 183} 184 185void wxComboBox::SetString(unsigned int n, const wxString& s) 186{ 187 wxXmString text(s); 188 Widget listBox = GetXmList(this); 189 190 // delete the item and add it again. 191 // FIXME isn't there a way to change it in place? 192 XmListDeletePos (listBox, n+1); 193 XmListAddItem (listBox, text(), n+1); 194} 195 196void wxComboBox::SetValue(const wxString& value) 197{ 198 m_inSetValue = true; 199 200 // Fix crash; probably an OpenMotif bug 201 const char* val = value.c_str() ? value.c_str() : ""; 202 XtVaSetValues( GetXmText(this), 203 XmNvalue, wxConstCast(val, char), 204 NULL); 205 206 m_inSetValue = false; 207} 208 209int wxComboBox::DoAppend(const wxString& item) 210{ 211 wxXmString str( item.c_str() ); 212 XmComboBoxAddItem((Widget) m_mainWidget, str(), 0, False); 213 m_noStrings ++; 214 AdjustDropDownListSize(); 215 216 return GetCount() - 1; 217} 218 219int wxComboBox::DoInsert(const wxString& item, unsigned int pos) 220{ 221 wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into sorted list")); 222 wxCHECK_MSG(IsValidInsert(pos), -1, wxT("invalid index")); 223 224 if (pos == GetCount()) 225 return DoAppend(item); 226 227 wxXmString str( item.c_str() ); 228 XmComboBoxAddItem((Widget) m_mainWidget, str(), pos+1, False); 229 m_noStrings ++; 230 AdjustDropDownListSize(); 231 232 return GetCount() - 1; 233} 234 235void wxComboBox::Delete(unsigned int n) 236{ 237#ifdef LESSTIF_VERSION 238 XmListDeletePos (GetXmList(this), n + 1); 239#else 240 XmComboBoxDeletePos((Widget) m_mainWidget, n+1); 241#endif 242 243 m_clientDataDict.Delete(n, HasClientObjectData()); 244 m_noStrings--; 245 246 AdjustDropDownListSize(); 247} 248 249void wxComboBox::Clear() 250{ 251#ifdef LESSTIF_VERSION 252 XmListDeleteAllItems (GetXmList(this)); 253#else 254 while(m_noStrings > 0) 255 { 256 XmComboBoxDeletePos((Widget) m_mainWidget, m_noStrings--); 257 } 258#endif 259 260 if ( HasClientObjectData() ) 261 m_clientDataDict.DestroyData(); 262 m_noStrings = 0; 263 AdjustDropDownListSize(); 264} 265 266void wxComboBox::SetSelection (int n) 267{ 268 m_inSetSelection = true; 269 270#if wxCHECK_LESSTIF() 271 XmListSelectPos (GetXmList(this), n + 1, false); 272 SetValue(GetString(n)); 273#else 274#if 0 275 wxXmString str(GetString(n).c_str()); 276 XmComboBoxSelectItem((Widget) m_mainWidget, str()); 277#endif 278 XtVaSetValues( (Widget)m_mainWidget, 279 XmNselectedPosition, n, 280 NULL ); 281#endif 282 283 m_inSetSelection = false; 284} 285 286int wxComboBox::GetSelection (void) const 287{ 288 return wxDoGetSelectionInList( GetXmList( this ) ); 289} 290 291wxString wxComboBox::GetString(unsigned int n) const 292{ 293 return wxDoGetStringInList( GetXmList(this), n ); 294} 295 296int wxComboBox::FindString(const wxString& s, bool WXUNUSED(bCase)) const 297{ 298 // FIXME: back to base class for not supported value of bCase 299 300 return wxDoFindStringInList( GetXmList( this ), s ); 301} 302 303// Clipboard operations 304void wxComboBox::Copy() 305{ 306 XmTextCopy( GetXmText(this), CurrentTime ); 307} 308 309void wxComboBox::Cut() 310{ 311 XmTextCut( GetXmText(this), CurrentTime ); 312} 313 314void wxComboBox::Paste() 315{ 316 XmTextPaste( GetXmText(this) ); 317} 318 319void wxComboBox::SetEditable(bool WXUNUSED(editable)) 320{ 321 // TODO 322} 323 324void wxComboBox::SetInsertionPoint(long pos) 325{ 326 XmTextSetInsertionPosition( GetXmText(this), (XmTextPosition)pos ); 327} 328 329void wxComboBox::SetInsertionPointEnd() 330{ 331 SetInsertionPoint( GetLastPosition() ); 332} 333 334long wxComboBox::GetInsertionPoint() const 335{ 336 return (long)XmTextGetInsertionPosition( GetXmText(this) ); 337} 338 339wxTextPos wxComboBox::GetLastPosition() const 340{ 341 XmTextPosition pos = XmTextGetLastPosition( GetXmText(this) ); 342 return (long)pos; 343} 344 345void wxComboBox::Replace(long from, long to, const wxString& value) 346{ 347 XmTextReplace( GetXmText(this), (XmTextPosition)from, (XmTextPosition)to, 348 wxConstCast(value.c_str(), char) ); 349} 350 351void wxComboBox::Remove(long from, long to) 352{ 353 SetSelection( from, to ); 354 XmTextRemove( GetXmText(this) ); 355} 356 357void wxComboBox::SetSelection(long from, long to) 358{ 359 if( to == -1 ) 360 to = GetLastPosition(); 361 362 XmTextSetSelection( GetXmText(this), (XmTextPosition)from, 363 (XmTextPosition)to, (Time)0 ); 364} 365 366void wxComboBoxCallback (Widget WXUNUSED(w), XtPointer clientData, 367 XmComboBoxCallbackStruct * cbs) 368{ 369 wxComboBox *item = (wxComboBox *) clientData; 370 371 if( item->m_inSetSelection ) return; 372 373 switch (cbs->reason) 374 { 375 case XmCR_SELECT: 376#if 0 377 case XmCR_SINGLE_SELECT: 378 case XmCR_BROWSE_SELECT: 379#endif 380 { 381 wxCommandEvent event (wxEVT_COMMAND_COMBOBOX_SELECTED, 382 item->GetId()); 383 int idx = cbs->item_position; 384 event.SetInt(idx); 385 event.SetString( item->GetString (idx) ); 386 if ( item->HasClientObjectData() ) 387 event.SetClientObject( item->GetClientObject(idx) ); 388 else if ( item->HasClientUntypedData() ) 389 event.SetClientData( item->GetClientData(idx) ); 390 event.SetExtraLong(true); 391 event.SetEventObject(item); 392 item->GetEventHandler()->ProcessEvent(event); 393 break; 394 } 395 case XmCR_VALUE_CHANGED: 396 { 397 wxCommandEvent event (wxEVT_COMMAND_TEXT_UPDATED, item->GetId()); 398 event.SetInt(-1); 399 event.SetString( item->GetValue() ); 400 event.SetExtraLong(true); 401 event.SetEventObject(item); 402 item->GetEventHandler()->ProcessEvent(event); 403 break; 404 } 405 default: 406 break; 407 } 408} 409 410void wxComboBox::ChangeFont(bool keepOriginalSize) 411{ 412 if( m_font.Ok() ) 413 { 414 wxDoChangeFont( GetXmText(this), m_font ); 415 wxDoChangeFont( GetXmList(this), m_font ); 416 } 417 418 // Don't use the base class wxChoice's ChangeFont 419 wxWindow::ChangeFont(keepOriginalSize); 420} 421 422void wxComboBox::ChangeBackgroundColour() 423{ 424 wxWindow::ChangeBackgroundColour(); 425} 426 427void wxComboBox::ChangeForegroundColour() 428{ 429 wxWindow::ChangeForegroundColour(); 430} 431 432wxSize wxComboBox::DoGetBestSize() const 433{ 434 if( (GetWindowStyle() & wxCB_DROPDOWN) == wxCB_DROPDOWN || 435 (GetWindowStyle() & wxCB_READONLY) == wxCB_READONLY ) 436 { 437 Dimension arrowW, arrowS, highlight, xmargin, ymargin, shadow; 438 439 XtVaGetValues( (Widget)m_mainWidget, 440 XmNarrowSize, &arrowW, 441 XmNarrowSpacing, &arrowS, 442 XmNhighlightThickness, &highlight, 443 XmNmarginWidth, &xmargin, 444 XmNmarginHeight, &ymargin, 445 XmNshadowThickness, &shadow, 446 NULL ); 447 448 wxSize listSize = wxDoGetListBoxBestSize( GetXmList(this), this ); 449 wxSize textSize = wxDoGetSingleTextCtrlBestSize( GetXmText(this), 450 this ); 451 452 // FIXME arbitrary constants 453 return wxSize( listSize.x + arrowW + arrowS + 2 * highlight 454 + 2 * shadow + 2 * xmargin , 455 textSize.y + 2 * highlight + 2 * ymargin + 2 * shadow ); 456 } 457 else 458 return wxWindow::DoGetBestSize(); 459} 460 461#endif // XmVersion >= 2000 462 463#endif // wxUSE_COMBOBOX 464