]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/motif/listbox.cpp
missing commit
[wxWidgets.git] / src / motif / listbox.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/motif/listbox.cpp
3// Purpose: wxListBox
4// Author: Julian Smart
5// Modified by:
6// Created: 17/09/98
7// RCS-ID: $Id$
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_LISTBOX
16
17#include "wx/listbox.h"
18
19#ifndef WX_PRECOMP
20 #include "wx/dynarray.h"
21 #include "wx/log.h"
22 #include "wx/utils.h"
23 #include "wx/settings.h"
24 #include "wx/arrstr.h"
25#endif
26
27#ifdef __VMS__
28#pragma message disable nosimpint
29#endif
30#include <Xm/List.h>
31#ifdef __VMS__
32#pragma message enable nosimpint
33#endif
34#include "wx/motif/private.h"
35
36static void wxListBoxCallback(Widget w,
37 XtPointer clientData,
38 XmListCallbackStruct * cbs);
39
40// ----------------------------------------------------------------------------
41// wxSizeKeeper
42// ----------------------------------------------------------------------------
43
44// helper class to reduce code duplication
45class wxSizeKeeper
46{
47 int m_x, m_y;
48 int m_w, m_h;
49 wxWindow* m_wnd;
50public:
51 wxSizeKeeper( wxWindow* w )
52 : m_wnd( w )
53 {
54 m_wnd->GetSize( &m_w, &m_h );
55 m_wnd->GetPosition( &m_x, &m_y );
56 }
57
58 void Restore()
59 {
60 int x, y;
61
62 m_wnd->GetSize( &x, &y );
63 if( x != m_x || y != m_y )
64 m_wnd->SetSize( m_x, m_y, m_w, m_h );
65 }
66};
67
68// ============================================================================
69// list box control implementation
70// ============================================================================
71
72// Listbox item
73wxListBox::wxListBox()
74{
75 m_noItems = 0;
76}
77
78bool wxListBox::Create(wxWindow *parent, wxWindowID id,
79 const wxPoint& pos,
80 const wxSize& size,
81 int n, const wxString choices[],
82 long style,
83 const wxValidator& validator,
84 const wxString& name)
85{
86 if( !wxControl::CreateControl( parent, id, pos, size, style,
87 validator, name ) )
88 return false;
89 PreCreation();
90
91 m_noItems = (unsigned int)n;
92
93 Widget parentWidget = (Widget) parent->GetClientWidget();
94 Display* dpy = XtDisplay(parentWidget);
95
96 Arg args[4];
97 int count = 0;
98 XtSetArg( args[count], XmNlistSizePolicy, XmCONSTANT ); ++count;
99 XtSetArg( args[count], XmNselectionPolicy,
100 ( m_windowStyle & wxLB_MULTIPLE ) ? XmMULTIPLE_SELECT :
101 ( m_windowStyle & wxLB_EXTENDED ) ? XmEXTENDED_SELECT :
102 XmBROWSE_SELECT );
103 ++count;
104 if( m_font.IsOk() )
105 {
106 XtSetArg( args[count],
107 (String)wxFont::GetFontTag(), m_font.GetFontTypeC(dpy) );
108 ++count;
109 }
110 if( m_windowStyle & wxLB_ALWAYS_SB )
111 {
112 XtSetArg( args[count], XmNscrollBarDisplayPolicy, XmSTATIC );
113 ++count;
114 }
115
116 Widget listWidget =
117 XmCreateScrolledList(parentWidget,
118 name.char_str(), args, count);
119
120 m_mainWidget = (WXWidget) listWidget;
121
122 Set(n, choices);
123
124 XtManageChild (listWidget);
125
126 wxSize best = GetBestSize();
127 if( size.x != -1 ) best.x = size.x;
128 if( size.y != -1 ) best.y = size.y;
129
130 XtAddCallback (listWidget,
131 XmNbrowseSelectionCallback,
132 (XtCallbackProc) wxListBoxCallback,
133 (XtPointer) this);
134 XtAddCallback (listWidget,
135 XmNextendedSelectionCallback,
136 (XtCallbackProc) wxListBoxCallback,
137 (XtPointer) this);
138 XtAddCallback (listWidget,
139 XmNmultipleSelectionCallback,
140 (XtCallbackProc) wxListBoxCallback,
141 (XtPointer) this);
142 XtAddCallback (listWidget,
143 XmNdefaultActionCallback,
144 (XtCallbackProc) wxListBoxCallback,
145 (XtPointer) this);
146
147 PostCreation();
148 AttachWidget (parent, m_mainWidget, (WXWidget) NULL,
149 pos.x, pos.y, best.x, best.y);
150
151 return true;
152}
153
154bool wxListBox::Create(wxWindow *parent, wxWindowID id,
155 const wxPoint& pos,
156 const wxSize& size,
157 const wxArrayString& choices,
158 long style,
159 const wxValidator& validator,
160 const wxString& name)
161{
162 wxCArrayString chs(choices);
163 return Create(parent, id, pos, size, chs.GetCount(), chs.GetStrings(),
164 style, validator, name);
165}
166
167void wxListBox::SetSelectionPolicy()
168{
169 Widget listBox = (Widget)m_mainWidget;
170 Arg args[3];
171
172 XtSetArg( args[0], XmNlistSizePolicy, XmCONSTANT );
173
174 XtSetArg( args[1], XmNselectionPolicy,
175 ( m_windowStyle & wxLB_MULTIPLE ) ? XmMULTIPLE_SELECT :
176 ( m_windowStyle & wxLB_EXTENDED ) ? XmEXTENDED_SELECT :
177 XmBROWSE_SELECT );
178
179 XtSetValues( listBox, args, 2 );
180}
181
182void wxListBox::DoSetFirstItem( int N )
183{
184 int count, length;
185
186 if (!IsValid(N))
187 return;
188
189 XtVaGetValues ((Widget) m_mainWidget,
190 XmNvisibleItemCount, &count,
191 XmNitemCount, &length,
192 NULL);
193 if ((N + count) >= length)
194 N = length - count;
195 XmListSetPos ((Widget) m_mainWidget, N + 1);
196}
197
198void wxListBox::DoDeleteOneItem(unsigned int n)
199{
200 Widget listBox = (Widget) m_mainWidget;
201
202 XmListDeletePos (listBox, n + 1);
203
204 wxListBoxBase::DoDeleteOneItem(n);
205 m_noItems --;
206}
207
208int wxDoFindStringInList(Widget w, const wxString& s)
209{
210 wxXmString str( s );
211 int *positions = NULL;
212 int no_positions = 0;
213 bool success = XmListGetMatchPos (w, str(),
214 &positions, &no_positions);
215
216 if (success && positions)
217 {
218 int pos = positions[0];
219 XtFree ((char *) positions);
220 return pos - 1;
221 }
222 else
223 return -1;
224}
225
226int wxListBox::FindString(const wxString& s, bool WXUNUSED(bCase)) const
227{
228 // FIXME: back to base class for not supported value of bCase
229
230 return wxDoFindStringInList( (Widget)m_mainWidget, s );
231}
232
233void wxListBox::DoClear()
234{
235 if (!m_noItems)
236 return;
237
238 wxSizeKeeper sk( this );
239 Widget listBox = (Widget) m_mainWidget;
240
241 XmListDeleteAllItems (listBox);
242
243 sk.Restore();
244
245 wxListBoxBase::DoClear();
246 m_noItems = 0;
247}
248
249void wxListBox::DoSetSelection(int N, bool select)
250{
251 m_inSetValue = true;
252 if (select)
253 {
254#if 0
255 if (m_windowStyle & wxLB_MULTIPLE)
256 {
257 int *selections = NULL;
258 int n = GetSelections (&selections);
259
260 // This hack is supposed to work, to make it possible
261 // to select more than one item, but it DOESN'T under Motif 1.1.
262
263 XtVaSetValues ((Widget) m_mainWidget,
264 XmNselectionPolicy, XmMULTIPLE_SELECT,
265 NULL);
266
267 int i;
268 for (i = 0; i < n; i++)
269 XmListSelectPos ((Widget) m_mainWidget,
270 selections[i] + 1, False);
271
272 XmListSelectPos ((Widget) m_mainWidget, N + 1, False);
273
274 XtVaSetValues ((Widget) m_mainWidget,
275 XmNselectionPolicy, XmEXTENDED_SELECT,
276 NULL);
277 }
278 else
279#endif // 0
280 XmListSelectPos ((Widget) m_mainWidget, N + 1, False);
281
282 }
283 else
284 XmListDeselectPos ((Widget) m_mainWidget, N + 1);
285
286 m_inSetValue = false;
287}
288
289bool wxListBox::IsSelected(int N) const
290{
291 // In Motif, no simple way to determine if the item is selected.
292 wxArrayInt theSelections;
293 int count = GetSelections (theSelections);
294 if (count == 0)
295 return false;
296 else
297 {
298 int j;
299 for (j = 0; j < count; j++)
300 if (theSelections[j] == N)
301 return true;
302 }
303 return false;
304}
305
306// Return number of selections and an array of selected integers
307int wxListBox::GetSelections(wxArrayInt& aSelections) const
308{
309 aSelections.Empty();
310
311 Widget listBox = (Widget) m_mainWidget;
312 int *posList = NULL;
313 int posCnt = 0;
314 bool flag = XmListGetSelectedPos (listBox, &posList, &posCnt);
315 if (flag)
316 {
317 if (posCnt > 0)
318 {
319 aSelections.Alloc(posCnt);
320
321 int i;
322 for (i = 0; i < posCnt; i++)
323 aSelections.Add(posList[i] - 1);
324
325 XtFree ((char *) posList);
326 return posCnt;
327 }
328 else
329 return 0;
330 }
331 else
332 return 0;
333}
334
335// Get single selection, for single choice list items
336int wxDoGetSelectionInList(Widget listBox)
337{
338 int *posList = NULL;
339 int posCnt = 0;
340 bool flag = XmListGetSelectedPos (listBox, &posList, &posCnt);
341 if (flag)
342 {
343 int id = -1;
344 if (posCnt > 0)
345 id = posList[0] - 1;
346 XtFree ((char *) posList);
347 return id;
348 }
349 else
350 return -1;
351}
352
353int wxListBox::GetSelection() const
354{
355 return wxDoGetSelectionInList((Widget) m_mainWidget);
356}
357
358// Find string for position
359wxString wxDoGetStringInList( Widget listBox, int n )
360{
361 XmString *strlist;
362 int count;
363 XtVaGetValues( listBox,
364 XmNitemCount, &count,
365 XmNitems, &strlist,
366 NULL );
367 if( n < count && n >= 0 )
368 return wxXmStringToString( strlist[n] );
369 else
370 return wxEmptyString;
371}
372
373wxString wxListBox::GetString(unsigned int n) const
374{
375 return wxDoGetStringInList( (Widget)m_mainWidget, n );
376}
377
378int wxListBox::DoInsertItems(const wxArrayStringsAdapter & items,
379 unsigned int pos,
380 void **clientData, wxClientDataType type)
381{
382 Widget listBox = (Widget) m_mainWidget;
383
384 const unsigned int numItems = items.GetCount();
385
386 XmString *text = new XmString[numItems];
387 unsigned int i;
388#if XmVersion > 1001
389 for (i = 0; i < numItems; i++)
390 {
391 text[i] = wxStringToXmString(items[i]);
392 }
393 XmListAddItemsUnselected(listBox, text, numItems, GetMotifPosition(pos));
394 InsertNewItemsClientData(pos, numItems, clientData, type);
395#else
396 AllocClientData(numItems);
397
398 unsigned int idx = pos;
399 for ( i = 0; i < numItems; i++, idx++ )
400 {
401 text[i] = wxStringToXmString(items[i]);
402 XmListAddItemUnselected(listBox, text[i], GetMotifPosition(idx));
403 InsertNewItemClientData(idx, clientData, i, type);
404 }
405#endif
406 for (i = 0; i < numItems; i++)
407 XmStringFree(text[i]);
408 delete[] text;
409
410 m_noItems += numItems;
411
412 SetSelectionPolicy();
413
414 return pos + numItems - 1;
415}
416
417void wxListBox::SetString(unsigned int n, const wxString& s)
418{
419 wxSizeKeeper sk( this );
420 Widget listBox = (Widget) m_mainWidget;
421
422 wxXmString text( s );
423
424 // delete the item and add it again.
425 // FIXME isn't there a way to change it in place?
426 XmListDeletePos (listBox, n+1);
427 XmListAddItem (listBox, text(), n+1);
428
429 sk.Restore();
430}
431
432void wxListBox::Command (wxCommandEvent & event)
433{
434 if (event.GetExtraLong())
435 SetSelection (event.GetInt());
436 else
437 {
438 Deselect (event.GetInt());
439 return;
440 }
441 ProcessCommand (event);
442}
443
444void wxListBoxCallback (Widget WXUNUSED(w), XtPointer clientData,
445 XmListCallbackStruct * cbs)
446{
447 wxListBox *item = (wxListBox *) clientData;
448
449 if (item->InSetValue())
450 return;
451
452 wxEventType evtType;
453
454 if( cbs->reason == XmCR_DEFAULT_ACTION )
455 evtType = wxEVT_LISTBOX_DCLICK;
456 else
457 evtType = wxEVT_LISTBOX;
458
459 int n = cbs->item_position - 1;
460 wxCommandEvent event (evtType, item->GetId());
461 if ( item->HasClientObjectData() )
462 event.SetClientObject( item->GetClientObject(n) );
463 else if ( item->HasClientUntypedData() )
464 event.SetClientData( item->GetClientData(n) );
465 event.SetInt(n);
466 event.SetExtraLong(true);
467 event.SetEventObject(item);
468 event.SetString( item->GetString( n ) );
469
470 int x = -1;
471 if( NULL != cbs->event && cbs->event->type == ButtonRelease )
472 {
473 XButtonEvent* evt = (XButtonEvent*)cbs->event;
474
475 x = evt->x;
476 }
477
478 switch (cbs->reason)
479 {
480 case XmCR_MULTIPLE_SELECT:
481 case XmCR_BROWSE_SELECT:
482#if wxUSE_CHECKLISTBOX
483 item->DoToggleItem( n, x );
484#endif
485 case XmCR_DEFAULT_ACTION:
486 item->HandleWindowEvent(event);
487 break;
488 case XmCR_EXTENDED_SELECT:
489 switch (cbs->selection_type)
490 {
491 case XmINITIAL:
492 case XmADDITION:
493 case XmMODIFICATION:
494 item->DoToggleItem( n, x );
495 item->HandleWindowEvent(event);
496 break;
497 }
498 break;
499 }
500}
501
502WXWidget wxListBox::GetTopWidget() const
503{
504 return (WXWidget) XtParent( (Widget) m_mainWidget );
505}
506
507void wxListBox::ChangeBackgroundColour()
508{
509 wxWindow::ChangeBackgroundColour();
510
511 Widget parent = XtParent ((Widget) m_mainWidget);
512 Widget hsb, vsb;
513
514 XtVaGetValues (parent,
515 XmNhorizontalScrollBar, &hsb,
516 XmNverticalScrollBar, &vsb,
517 NULL);
518
519 /* TODO: should scrollbars be affected? Should probably have separate
520 * function to change them (by default, taken from wxSystemSettings)
521 */
522 wxColour backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
523 wxDoChangeBackgroundColour((WXWidget) hsb, backgroundColour, true);
524 wxDoChangeBackgroundColour((WXWidget) vsb, backgroundColour, true);
525
526 XtVaSetValues (hsb,
527 XmNtroughColor, backgroundColour.AllocColour(XtDisplay(hsb)),
528 NULL);
529 XtVaSetValues (vsb,
530 XmNtroughColor, backgroundColour.AllocColour(XtDisplay(vsb)),
531 NULL);
532
533 // MBN: why change parent's background? It looks really ugly.
534 // wxDoChangeBackgroundColour((WXWidget) parent, m_backgroundColour, true);
535}
536
537void wxListBox::ChangeForegroundColour()
538{
539 wxWindow::ChangeForegroundColour();
540
541 Widget parent = XtParent ((Widget) m_mainWidget);
542 Widget hsb, vsb;
543
544 XtVaGetValues(parent,
545 XmNhorizontalScrollBar, &hsb,
546 XmNverticalScrollBar, &vsb,
547 NULL);
548
549 /* TODO: should scrollbars be affected? Should probably have separate
550 function to change them (by default, taken from wxSystemSettings)
551
552 wxDoChangeForegroundColour((WXWidget) hsb, m_foregroundColour);
553 wxDoChangeForegroundColour((WXWidget) vsb, m_foregroundColour);
554 wxDoChangeForegroundColour((WXWidget) parent, m_foregroundColour);
555 */
556}
557
558unsigned int wxListBox::GetCount() const
559{
560 return m_noItems;
561}
562
563#define LIST_SCROLL_SPACING 6
564
565wxSize wxDoGetListBoxBestSize( Widget listWidget, const wxWindow* window )
566{
567 int max;
568 Dimension spacing, highlight, xmargin, ymargin, shadow;
569 int width = 0;
570 int x, y;
571
572 XtVaGetValues( listWidget,
573 XmNitemCount, &max,
574 XmNlistSpacing, &spacing,
575 XmNhighlightThickness, &highlight,
576 XmNlistMarginWidth, &xmargin,
577 XmNlistMarginHeight, &ymargin,
578 XmNshadowThickness, &shadow,
579 NULL );
580
581 for( size_t i = 0; i < (size_t)max; ++i )
582 {
583 window->GetTextExtent( wxDoGetStringInList( listWidget, i ), &x, &y );
584 width = wxMax( width, x );
585 }
586
587 // use some arbitrary value if there are no strings
588 if( width == 0 )
589 width = 100;
590
591 // get my
592 window->GetTextExtent( "v", &x, &y );
593
594 // make it a little larger than widest string, plus the scrollbar
595 width += wxSystemSettings::GetMetric( wxSYS_VSCROLL_X )
596 + 2 * highlight + LIST_SCROLL_SPACING + 2 * xmargin + 2 * shadow;
597
598 // at least 3 items, at most 10
599 int height = wxMax( 3, wxMin( 10, max ) ) *
600 ( y + spacing + 2 * highlight ) + 2 * ymargin + 2 * shadow;
601
602 return wxSize( width, height );
603}
604
605wxSize wxListBox::DoGetBestSize() const
606{
607 return wxDoGetListBoxBestSize( (Widget)m_mainWidget, this );
608}
609
610#endif // wxUSE_LISTBOX