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