Finished native wxComboBox implementation; it still needs some testing.
[wxWidgets.git] / src / motif / combobox_native.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/setup.h"
13
14 #if wxUSE_COMBOBOX
15
16 #include "wx/combobox.h"
17
18 #ifdef __VMS__
19 #pragma message disable nosimpint
20 #endif
21 #include <Xm/Xm.h>
22 #ifdef __VMS__
23 #pragma message enable nosimpint
24 #endif
25
26 // use the new, shiny combobox for Motif 2.x
27 #if (XmVersion >= 2000)
28
29 #ifdef __VMS__
30 #pragma message disable nosimpint
31 #endif
32 #include <Xm/ComboBox.h>
33 #include <Xm/Text.h>
34 #include <Xm/List.h>
35 #ifdef __VMS__
36 #pragma message enable nosimpint
37 #endif
38
39 #include "wx/motif/private.h"
40
41 // utility
42 static Widget GetXmList( const wxComboBox* cb )
43 {
44 Widget ret;
45 XtVaGetValues( (Widget)cb->GetMainWidget(),
46 XmNlist, &ret,
47 NULL );
48
49 return ret;
50 }
51
52 static Widget GetXmText( const wxComboBox* cb )
53 {
54 Widget ret;
55 XtVaGetValues( (Widget)cb->GetMainWidget(),
56 XmNtextField, &ret,
57 NULL );
58
59 return ret;
60 }
61
62 void wxComboBoxCallback (Widget w, XtPointer clientData,
63 XmComboBoxCallbackStruct * cbs);
64
65 IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
66
67 bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
68 const wxString& value,
69 const wxPoint& pos,
70 const wxSize& size,
71 int n, const wxString choices[],
72 long style,
73 const wxValidator& validator,
74 const wxString& name)
75 {
76 if( !CreateControl( parent, id, pos, size, style, validator, name ) )
77 return false;
78
79 Widget parentWidget = (Widget) parent->GetClientWidget();
80
81 int cb_type = ( style & wxCB_SIMPLE ) ? XmCOMBO_BOX :
82 ( style & wxCB_READONLY ) ? XmDROP_DOWN_LIST :
83 ( style & wxCB_DROPDOWN ) ? XmDROP_DOWN_COMBO_BOX :
84 // default to wxCB_DROPDOWN
85 XmDROP_DOWN_COMBO_BOX;
86
87 Widget buttonWidget= XtVaCreateManagedWidget(name.c_str(),
88 xmComboBoxWidgetClass, parentWidget,
89 XmNcomboBoxType, cb_type,
90 NULL);
91
92 m_mainWidget = (Widget) buttonWidget;
93
94 int i;
95 for ( i = 0; i < n; ++i)
96 Append( choices[i] );
97
98 XtManageChild (buttonWidget);
99
100 SetValue(value);
101
102 ChangeFont(false);
103
104 XtAddCallback (buttonWidget, XmNselectionCallback,
105 (XtCallbackProc) wxComboBoxCallback,
106 (XtPointer) this);
107 XtAddCallback (GetXmText(this), XmNvalueChangedCallback,
108 (XtCallbackProc) wxComboBoxCallback,
109 (XtPointer) this);
110
111 SetCanAddEventHandler(true);
112 AttachWidget (parent, m_mainWidget, (WXWidget) NULL,
113 pos.x, pos.y, size.x, size.y);
114
115 XtVaSetValues (GetXmList(this),
116 XmNvisibleItemCount, 10,
117 NULL);
118
119 ChangeBackgroundColour();
120
121 return true;
122 }
123
124 wxComboBox::~wxComboBox()
125 {
126 DetachWidget((Widget) m_mainWidget); // Removes event handlers
127 XtDestroyWidget((Widget) m_mainWidget);
128 m_mainWidget = (WXWidget) 0;
129 if ( HasClientObjectData() )
130 m_clientDataDict.DestroyData();
131 }
132
133 void wxComboBox::DoSetSize(int x, int y, int width, int height, int sizeFlags)
134 {
135 // Necessary so it doesn't call wxChoice::SetSize
136 wxWindow::DoSetSize(x, y, width, DoGetBestSize().y, sizeFlags);
137 }
138
139 wxString wxComboBox::GetValue() const
140 {
141 char* s = XmTextGetString (GetXmText (this));
142 wxString str(s);
143 if (s)
144 XtFree (s);
145 return str;
146 }
147
148 void wxComboBox::SetString(int n, const wxString& s)
149 {
150 wxXmString text(s);
151 Widget listBox = GetXmList(this);
152
153 // delete the item and add it again.
154 // FIXME isn't there a way to change it in place?
155 XmListDeletePos (listBox, n+1);
156 XmListAddItem (listBox, text(), n+1);
157 }
158
159 void wxComboBox::SetValue(const wxString& value)
160 {
161 m_inSetValue = true;
162
163 XtVaSetValues( GetXmText(this),
164 XmNvalue, (char *)value.c_str(),
165 NULL);
166
167 m_inSetValue = false;
168 }
169
170 int wxComboBox::DoAppend(const wxString& item)
171 {
172 wxXmString str( item.c_str() );
173 XmComboBoxAddItem((Widget) m_mainWidget, str(), 0, False);
174 m_stringList.Add(item);
175 m_noStrings ++;
176
177 return GetCount() - 1;
178 }
179
180 void wxComboBox::Delete(int n)
181 {
182 #ifdef LESSTIF_VERSION
183 XmListDeletePos (GetXmList(this), n + 1);
184 #else
185 XmComboBoxDeletePos((Widget) m_mainWidget, n+1);
186 #endif
187
188 wxStringList::Node *node = m_stringList.Item(n);
189 if (node)
190 {
191 delete[] node->GetData();
192 delete node;
193 }
194 m_clientDataDict.Delete(n, HasClientObjectData());
195 m_noStrings--;
196 }
197
198 void wxComboBox::Clear()
199 {
200 #ifdef LESSTIF_VERSION
201 XmListDeleteAllItems (GetXmList(this));
202 #else
203 while(m_noStrings > 0)
204 {
205 XmComboBoxDeletePos((Widget) m_mainWidget, m_noStrings--);
206 }
207 #endif
208
209 m_stringList.Clear();
210
211 if ( HasClientObjectData() )
212 m_clientDataDict.DestroyData();
213 m_noStrings = 0;
214 }
215
216 void wxComboBox::SetSelection (int n)
217 {
218 #ifdef LESSTIF_VERSION
219 XmListSelectPos (GetXmList(this), n + 1, false);
220 SetValue(GetString(n));
221 #else
222 wxXmString str( GetString(n).c_str() );
223 XmComboBoxSelectItem((Widget) m_mainWidget, str());
224 #if 0
225 // does it work for Motif
226 XtVaSetValues( (Widget)m_mainWidget,
227 XmNselectedPosition, n + 1,
228 NULL );
229 #endif
230 #endif
231 }
232
233 int wxComboBox::GetSelection (void) const
234 {
235 return wxDoGetSelectionInList( GetXmList( this ) );
236 }
237
238 wxString wxComboBox::GetString(int n) const
239 {
240 wxStringList::Node *node = m_stringList.Item(n);
241 if (node)
242 return wxString(node->GetData ());
243 else
244 return wxEmptyString;
245 }
246
247 int wxComboBox::FindString(const wxString& s) const
248 {
249 return wxDoFindStringInList( GetXmList( this ), s );
250 }
251
252 // Clipboard operations
253 void wxComboBox::Copy()
254 {
255 XmTextCopy( GetXmText(this), CurrentTime );
256 }
257
258 void wxComboBox::Cut()
259 {
260 XmTextCut( GetXmText(this), CurrentTime );
261 }
262
263 void wxComboBox::Paste()
264 {
265 XmTextPaste( GetXmText(this) );
266 }
267
268 void wxComboBox::SetEditable(bool WXUNUSED(editable))
269 {
270 // TODO
271 }
272
273 void wxComboBox::SetInsertionPoint(long pos)
274 {
275 XmTextSetInsertionPosition( GetXmText(this), (XmTextPosition)pos );
276 }
277
278 void wxComboBox::SetInsertionPointEnd()
279 {
280 SetInsertionPoint( GetLastPosition() );
281 }
282
283 long wxComboBox::GetInsertionPoint() const
284 {
285 return (long)XmTextGetInsertionPosition( GetXmText(this) );
286 }
287
288 long wxComboBox::GetLastPosition() const
289 {
290 XmTextPosition pos = XmTextGetLastPosition( GetXmText(this) );
291 return (long)pos;
292 }
293
294 void wxComboBox::Replace(long from, long to, const wxString& value)
295 {
296 XmTextReplace( GetXmText(this), (XmTextPosition)from, (XmTextPosition)to,
297 (char*)value.c_str() );
298 }
299
300 void wxComboBox::Remove(long from, long to)
301 {
302 SetSelection( from, to );
303 XmTextRemove( GetXmText(this) );
304 }
305
306 void wxComboBox::SetSelection(long from, long to)
307 {
308 if( to == -1 )
309 to = GetLastPosition();
310
311 XmTextSetSelection( GetXmText(this), (XmTextPosition)from,
312 (XmTextPosition)to, (Time)0 );
313 }
314
315 void wxComboBoxCallback (Widget WXUNUSED(w), XtPointer clientData,
316 XmComboBoxCallbackStruct * cbs)
317 {
318 wxComboBox *item = (wxComboBox *) clientData;
319
320 switch (cbs->reason)
321 {
322 case XmCR_SELECT:
323 #if 0
324 case XmCR_SINGLE_SELECT:
325 case XmCR_BROWSE_SELECT:
326 #endif
327 {
328 wxCommandEvent event (wxEVT_COMMAND_COMBOBOX_SELECTED,
329 item->GetId());
330 int idx = cbs->item_position - 1;
331 event.m_commandInt = idx;
332 event.m_commandString = item->GetString (idx);
333 if ( item->HasClientObjectData() )
334 event.SetClientObject( item->GetClientObject(idx) );
335 else if ( item->HasClientUntypedData() )
336 event.SetClientData( item->GetClientData(idx) );
337 event.m_extraLong = true;
338 event.SetEventObject(item);
339 item->ProcessCommand (event);
340 break;
341 }
342 case XmCR_VALUE_CHANGED:
343 {
344 wxCommandEvent event (wxEVT_COMMAND_TEXT_UPDATED, item->GetId());
345 event.m_commandInt = -1;
346 event.m_commandString = item->GetValue();
347 event.m_extraLong = true;
348 event.SetEventObject(item);
349 item->ProcessCommand (event);
350 break;
351 }
352 default:
353 break;
354 }
355 }
356
357 void wxComboBox::ChangeFont(bool keepOriginalSize)
358 {
359 // Don't use the base class wxChoice's ChangeFont
360 wxWindow::ChangeFont(keepOriginalSize);
361 }
362
363 void wxComboBox::ChangeBackgroundColour()
364 {
365 wxWindow::ChangeBackgroundColour();
366 }
367
368 void wxComboBox::ChangeForegroundColour()
369 {
370 wxWindow::ChangeForegroundColour();
371 }
372
373 wxSize wxComboBox::DoGetBestSize() const
374 {
375 return wxWindow::DoGetBestSize();
376 }
377
378 #endif // XmVersion >= 2000
379
380 #endif // wxUSE_COMBOBOX