]> git.saurik.com Git - wxWidgets.git/blob - src/motif/listbox.cpp
7425164595c3f0b37a3977c14f209cffc20a6ebf
[wxWidgets.git] / src / motif / listbox.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #ifdef __GNUG__
13 #pragma implementation "listbox.h"
14 #endif
15
16 #include "wx/listbox.h"
17 #include "wx/settings.h"
18 #include "wx/dynarray.h"
19 #include "wx/log.h"
20 #include "wx/utils.h"
21
22 #include <Xm/List.h>
23 #include "wx/motif/private.h"
24
25 #if !USE_SHARED_LIBRARY
26 IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl)
27 #endif
28
29 void wxListBoxCallback (Widget w, XtPointer clientData,
30 XmListCallbackStruct * cbs);
31
32 void wxListBoxDefaultActionProc (Widget list_w, XtPointer client_data, XmListCallbackStruct * cbs);
33
34 // ============================================================================
35 // list box control implementation
36 // ============================================================================
37
38 // Listbox item
39 wxListBox::wxListBox(): m_clientDataList(wxKEY_INTEGER)
40 {
41 m_noItems = 0;
42 m_selected = 0;
43 m_inSetValue = FALSE;
44 }
45
46 bool wxListBox::Create(wxWindow *parent, wxWindowID id,
47 const wxPoint& pos,
48 const wxSize& size,
49 int n, const wxString choices[],
50 long style,
51 const wxValidator& validator,
52 const wxString& name)
53 {
54 m_inSetValue = FALSE;
55 m_windowStyle = style;
56 m_noItems = n;
57 m_selected = 0;
58
59 SetName(name);
60 SetValidator(validator);
61
62 if (parent) parent->AddChild(this);
63
64 m_windowId = ( id == -1 ) ? (int)NewControlId() : id;
65
66 Widget parentWidget = (Widget) parent->GetClientWidget();
67
68 Arg args[3];
69 int count;
70 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
71 if (m_windowStyle & wxLB_MULTIPLE)
72 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
73 else if (m_windowStyle & wxLB_EXTENDED)
74 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
75 else
76 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
77 if (m_windowStyle & wxLB_ALWAYS_SB)
78 {
79 XtSetArg (args[2], XmNscrollBarDisplayPolicy, XmSTATIC);
80 count = 3;
81 }
82 else
83 count = 2;
84
85 Widget listWidget = XmCreateScrolledList (parentWidget, (char*) (const char*) name, args, count);
86
87 m_mainWidget = (WXWidget) listWidget;
88
89 XtManageChild (listWidget);
90
91 long width = size.x;
92 long height = size.y;
93 if (width == -1)
94 width = 150;
95 if (height == -1)
96 height = 80;
97
98 XtAddCallback (listWidget, XmNbrowseSelectionCallback, (XtCallbackProc) wxListBoxCallback,
99 (XtPointer) this);
100 XtAddCallback (listWidget, XmNextendedSelectionCallback, (XtCallbackProc) wxListBoxCallback,
101 (XtPointer) this);
102 XtAddCallback (listWidget, XmNmultipleSelectionCallback, (XtCallbackProc) wxListBoxCallback,
103 (XtPointer) this);
104
105 XtAddCallback (listWidget, XmNdefaultActionCallback, (XtCallbackProc) wxListBoxDefaultActionProc,
106 (XtPointer) this);
107
108 AttachWidget (parent, m_mainWidget, (WXWidget) NULL, pos.x, pos.y, width, height);
109
110 wxSystemSettings settings;
111 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
112
113 SetFont(* parent->GetFont());
114 ChangeColour(m_mainWidget);
115
116 return TRUE;
117 }
118
119 wxListBox::~wxListBox()
120 {
121 }
122
123 void wxListBox::SetFirstItem(int N)
124 {
125 int count, length;
126
127 if (N < 0)
128 return;
129 XtVaGetValues ((Widget) m_mainWidget,
130 XmNvisibleItemCount, &count,
131 XmNitemCount, &length,
132 NULL);
133 if ((N + count) >= length)
134 N = length - count;
135 XmListSetPos ((Widget) m_mainWidget, N + 1);
136 }
137
138 void wxListBox::SetFirstItem(const wxString& s)
139 {
140 int N = FindString (s);
141
142 if (N >= 0)
143 SetFirstItem (N);
144 }
145
146 void wxListBox::Delete(int N)
147 {
148 int width1, height1;
149 int width2, height2;
150 Widget listBox = (Widget) m_mainWidget;
151 GetSize (&width1, &height1);
152
153 bool managed = XtIsManaged(listBox);
154
155 if (managed)
156 XtUnmanageChild (listBox);
157
158 XmListDeletePos (listBox, N + 1);
159
160 if (managed)
161 XtManageChild (listBox);
162
163 GetSize (&width2, &height2);
164 // Correct for randomly resized listbox - bad boy, Motif!
165 if (width1 != width2 || height1 != height2)
166 SetSize (-1, -1, width1, height1);
167
168 // (JDH) need to add code here to take care of clientDataList
169 wxNode *node = m_clientDataList.Find((long)N); // get item from list
170 if (node) m_clientDataList.DeleteNode(node); // if existed then delete from list
171 node = m_clientDataList.First(); // we now have to adjust all keys that
172 while (node) // are >=N+1
173 { if (node->key.integer >= (long)(N+1)) // very ugly C++ wise but no other way
174 node->key.integer--; // to look at or change key value
175 node = node->Next();
176 }
177
178 m_noItems --;
179 }
180
181 void wxListBox::Append(const wxString& item)
182 {
183 int width1, height1;
184 int width2, height2;
185
186 Widget listBox = (Widget) m_mainWidget;
187 GetSize (&width1, &height1);
188
189 bool managed = XtIsManaged(listBox);
190
191 if (managed)
192 XtUnmanageChild (listBox);
193 int n;
194 XtVaGetValues (listBox, XmNitemCount, &n, NULL);
195 XmString text = XmStringCreateSimple ((char*) (const char*) item);
196 // XmListAddItem(listBox, text, n + 1);
197 XmListAddItemUnselected (listBox, text, 0);
198 XmStringFree (text);
199
200 // It seems that if the list is cleared, we must re-ask for
201 // selection policy!!
202 Arg args[3];
203 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
204 if (m_windowStyle & wxLB_MULTIPLE)
205 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
206 else if (m_windowStyle & wxLB_EXTENDED)
207 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
208 else
209 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
210 XtSetValues (listBox, args, 2);
211
212 if (managed)
213 XtManageChild (listBox);
214
215 GetSize (&width2, &height2);
216 // Correct for randomly resized listbox - bad boy, Motif!
217 if (width1 != width2 || height1 != height2)
218 SetSize (-1, -1, width1, height1);
219 m_noItems ++;
220 }
221
222 void wxListBox::Append(const wxString& item, char *clientData)
223 {
224 int width1, height1;
225 int width2, height2;
226
227 Widget listBox = (Widget) m_mainWidget;
228
229 GetSize (&width1, &height1);
230 Bool managed = XtIsManaged(listBox);
231
232 if (managed)
233 XtUnmanageChild (listBox);
234
235 int n;
236 XtVaGetValues (listBox, XmNitemCount, &n, NULL);
237 XmString text = XmStringCreateSimple ((char*) (const char*) item);
238 // XmListAddItem(listBox, text, n + 1);
239 XmListAddItemUnselected (listBox, text, 0);
240 XmStringFree (text);
241
242 // It seems that if the list is cleared, we must re-ask for
243 // selection policy!!
244 Arg args[3];
245 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
246 if (m_windowStyle & wxLB_MULTIPLE)
247 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
248 else if (m_windowStyle & wxLB_EXTENDED)
249 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
250 else
251 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
252 XtSetValues (listBox, args, 2);
253
254 m_clientDataList.Append ((long) n, (wxObject *) clientData);
255
256 if (managed)
257 XtManageChild (listBox);
258
259 GetSize (&width2, &height2);
260
261 // Correct for randomly resized listbox - bad boy, Motif!
262 if (width1 != width2 || height1 != height2)
263 SetSize (-1, -1, width1, height1);
264
265 m_noItems ++;
266 }
267
268 void wxListBox::Set(int n, const wxString *choices, char** clientData)
269 {
270 m_clientDataList.Clear();
271 int width1, height1;
272 int width2, height2;
273
274 Widget listBox = (Widget) m_mainWidget;
275 GetSize (&width1, &height1);
276
277 bool managed = XtIsManaged(listBox);
278
279 if (managed)
280 XtUnmanageChild (listBox);
281 /***
282 for (int i=0; i<n; i++)
283 {
284 XmString text = XmStringCreateSimple(choices[i]);
285 XmListAddItemUnselected(listBox, text, 0);
286 XmStringFree(text);
287 }
288 ***/
289 XmString *text = new XmString[n];
290 int i;
291 for (i = 0; i < n; i++)
292 text[i] = XmStringCreateSimple ((char*) (const char*) choices[i]);
293
294 if ( clientData )
295 for (i = 0; i < n; i++)
296 m_clientDataList.Append ((long) i, (wxObject *) clientData[i]);
297
298 XmListAddItems (listBox, text, n, 0);
299 for (i = 0; i < n; i++)
300 XmStringFree (text[i]);
301 delete[]text;
302
303 // It seems that if the list is cleared, we must re-ask for
304 // selection policy!!
305 Arg args[3];
306 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
307 if (m_windowStyle & wxLB_MULTIPLE)
308 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
309 else if (m_windowStyle & wxLB_EXTENDED)
310 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
311 else
312 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
313 XtSetValues (listBox, args, 2);
314
315 if (managed)
316 XtManageChild (listBox);
317
318 GetSize (&width2, &height2);
319 // Correct for randomly resized listbox - bad boy, Motif!
320 if (width1 != width2 || height1 != height2)
321 SetSize (-1, -1, width1, height1);
322
323 m_noItems = n;
324 }
325
326 int wxListBox::FindString(const wxString& s) const
327 {
328 XmString str = XmStringCreateSimple ((char*) (const char*) s);
329 int *positions = NULL;
330 int no_positions = 0;
331 bool success = XmListGetMatchPos ((Widget) m_mainWidget, str, &positions, &no_positions);
332 XmStringFree (str);
333 if (success)
334 {
335 int pos = positions[0];
336 if (positions)
337 XtFree ((char *) positions);
338 return pos - 1;
339 }
340 else
341 return -1;
342 }
343
344 void wxListBox::Clear()
345 {
346 if (m_noItems <= 0)
347 return;
348
349 int width1, height1;
350 int width2, height2;
351
352 Widget listBox = (Widget) m_mainWidget;
353 GetSize (&width1, &height1);
354
355 XmListDeleteAllItems (listBox);
356 m_clientDataList.Clear ();
357 GetSize (&width2, &height2);
358
359 // Correct for randomly resized listbox - bad boy, Motif!
360 if (width1 != width2 || height1 != height2)
361 SetSize (-1, -1, width1, height1);
362
363 m_noItems = 0;
364 }
365
366 void wxListBox::SetSelection(int N, bool select)
367 {
368 m_inSetValue = TRUE;
369 if (select)
370 {
371 /*
372 if (m_windowStyle & wxLB_MULTIPLE)
373 {
374 int *selections = NULL;
375 int n = GetSelections (&selections);
376
377 // This hack is supposed to work, to make it possible to select more
378 // than one item, but it DOESN'T under Motif 1.1.
379
380 XtVaSetValues ((Widget) m_mainWidget, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL);
381
382 int i;
383 for (i = 0; i < n; i++)
384 XmListSelectPos ((Widget) m_mainWidget, selections[i] + 1, FALSE);
385
386 XmListSelectPos ((Widget) m_mainWidget, N + 1, FALSE);
387
388 XtVaSetValues ((Widget) m_mainWidget, XmNselectionPolicy, XmEXTENDED_SELECT, NULL);
389 }
390 else
391 */
392 XmListSelectPos ((Widget) m_mainWidget, N + 1, FALSE);
393
394 }
395 else
396 XmListDeselectPos ((Widget) m_mainWidget, N + 1);
397
398 m_inSetValue = FALSE;
399 }
400
401 bool wxListBox::Selected(int N) const
402 {
403 // In Motif, no simple way to determine if the item is selected.
404 wxArrayInt theSelections;
405 int count = GetSelections (theSelections);
406 if (count == 0)
407 return FALSE;
408 else
409 {
410 int j;
411 for (j = 0; j < count; j++)
412 if (theSelections[j] == N)
413 return TRUE;
414 }
415 return FALSE;
416 }
417
418 void wxListBox::Deselect(int N)
419 {
420 XmListDeselectPos ((Widget) m_mainWidget, N + 1);
421 }
422
423 char *wxListBox::GetClientData(int N) const
424 {
425 wxNode *node = m_clientDataList.Find ((long) N);
426 if (node)
427 return (char *) node->Data ();
428 else
429 return NULL;
430 }
431
432 void wxListBox::SetClientData(int N, char *Client_data)
433 {
434 wxNode *node = m_clientDataList.Find ((long) N);
435 if (node)
436 node->SetData ((wxObject *)Client_data);
437 }
438
439 // Return number of selections and an array of selected integers
440 int wxListBox::GetSelections(wxArrayInt& aSelections) const
441 {
442 aSelections.Empty();
443
444 Widget listBox = (Widget) m_mainWidget;
445 int *posList = NULL;
446 int posCnt = 0;
447 bool flag = XmListGetSelectedPos (listBox, &posList, &posCnt);
448 if (flag)
449 {
450 if (posCnt > 0)
451 {
452 aSelections.Alloc(posCnt);
453
454 int i;
455 for (i = 0; i < posCnt; i++)
456 aSelections.Add(posList[i] - 1);
457
458 XtFree ((char *) posList);
459 return posCnt;
460 }
461 else
462 return 0;
463 }
464 else
465 return 0;
466 }
467
468 // Get single selection, for single choice list items
469 int wxListBox::GetSelection() const
470 {
471 Widget listBox = (Widget) m_mainWidget;
472 int *posList = NULL;
473 int posCnt = 0;
474 bool flag = XmListGetSelectedPos (listBox, &posList, &posCnt);
475 if (flag)
476 {
477 int id = -1;
478 if (posCnt > 0)
479 id = posList[0] - 1;
480 XtFree ((char *) posList);
481 return id;
482 }
483 else
484 return -1;
485 }
486
487 // Find string for position
488 wxString wxListBox::GetString(int N) const
489 {
490 Widget listBox = (Widget) m_mainWidget;
491 XmString *strlist;
492 int n;
493 XtVaGetValues (listBox, XmNitemCount, &n, XmNitems, &strlist, NULL);
494 if (N <= n && N >= 0)
495 {
496 char *txt;
497 if (XmStringGetLtoR (strlist[N], XmSTRING_DEFAULT_CHARSET, &txt))
498 {
499 wxString str(txt);
500 XtFree (txt);
501 return str;
502 }
503 else
504 return wxEmptyString;
505 }
506 else
507 return wxEmptyString;
508 }
509
510 void wxListBox::SetSize(int x, int y, int width, int height, int sizeFlags)
511 {
512 wxWindow::SetSize(x, y, width, height, sizeFlags);
513
514 // Check resulting size is correct
515 int tempW, tempH;
516 GetSize (&tempW, &tempH);
517
518 /*
519 if (tempW != width || tempH != height)
520 {
521 cout << "wxListBox::SetSize sizes not set correctly.");
522 }
523 */
524 }
525
526 void wxListBox::InsertItems(int nItems, const wxString items[], int pos)
527 {
528 int width1, height1;
529 int width2, height2;
530
531 Widget listBox = (Widget) m_mainWidget;
532
533 GetSize(&width1, &height1);
534
535 bool managed = XtIsManaged(listBox);
536
537 if (managed)
538 XtUnmanageChild(listBox);
539
540 XmString *text = new XmString[nItems];
541 int i;
542 // Steve Hammes: Motif 1.1 compatibility
543 // #if XmVersion > 1100
544 // Corrected by Sergey Krasnov from Steve Hammes' code
545 #if XmVersion > 1001
546 for (i = 0; i < nItems; i++)
547 text[i] = XmStringCreateSimple((char*) (const char*) items[i]);
548 XmListAddItemsUnselected(listBox, text, nItems, pos+1);
549 #else
550 for (i = 0; i < nItems; i++)
551 {
552 text[i] = XmStringCreateSimple((char*) (const char*) items[i]);
553 // XmListAddItemUnselected(listBox, text[i], i);
554 XmListAddItemUnselected(listBox, text[i], pos+i+1); // Another Sergey correction
555 }
556 #endif
557 for (i = 0; i < nItems; i++)
558 XmStringFree(text[i]);
559
560 delete[] text;
561
562 // It seems that if the list is cleared, we must re-ask for
563 // selection policy!!
564 Arg args[3];
565 XtSetArg(args[0], XmNlistSizePolicy, XmCONSTANT);
566 if (m_windowStyle & wxLB_MULTIPLE)
567 XtSetArg(args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
568 else if (m_windowStyle & wxLB_EXTENDED)
569 XtSetArg(args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
570 else XtSetArg(args[1], XmNselectionPolicy, XmBROWSE_SELECT);
571 XtSetValues(listBox,args,2) ;
572
573 if (managed)
574 XtManageChild(listBox);
575
576 GetSize(&width2, &height2);
577 // Correct for randomly resized listbox - bad boy, Motif!
578 if (width1 != width2 /*|| height1 != height2*/)
579 SetSize(-1, -1, width1, height1);
580
581 m_noItems += nItems;
582 }
583
584 void wxListBox::SetString(int N, const wxString& s)
585 {
586 int width1, height1;
587 int width2, height2;
588
589 Widget listBox = (Widget) m_mainWidget;
590 GetSize (&width1, &height1);
591
592 XmString text = XmStringCreateSimple ((char*) (const char*) s);
593
594 // WHAT'S THE MOTIF CALL TO SET THE TEXT OF AN EXISTING
595 // ITEM???
596 // There isn't one, so delete the item and add it again.
597 XmListDeletePos (listBox, N+1);
598 XmListAddItem (listBox, text, N+1);
599
600 XmStringFree(text);
601
602 /*
603 // It seems that if the list is cleared, we must re-ask for
604 // selection policy!!
605 Arg args[3];
606 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
607 if (m_windowStyle & wxLB_MULTIPLE)
608 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
609 else if (m_windowStyle & wxLB_EXTENDED)
610 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
611 else
612 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
613 XtSetValues (listBox, args, 2);
614 */
615
616 GetSize (&width2, &height2);
617 // Correct for randomly resized listbox - bad boy, Motif!
618 if (width1 != width2 || height1 != height2)
619 SetSize (-1, -1, width1, height1);
620 }
621
622 int wxListBox::Number () const
623 {
624 return m_noItems;
625 }
626
627 // For single selection items only
628 wxString wxListBox::GetStringSelection () const
629 {
630 int sel = GetSelection ();
631 if (sel > -1)
632 return this->GetString (sel);
633 else
634 return wxString("");
635 }
636
637 bool wxListBox::SetStringSelection (const wxString& s, bool flag)
638 {
639 int sel = FindString (s);
640 if (sel > -1)
641 {
642 SetSelection (sel, flag);
643 return TRUE;
644 }
645 else
646 return FALSE;
647 }
648
649 void wxListBox::Command (wxCommandEvent & event)
650 {
651 if (event.m_extraLong)
652 SetSelection (event.m_commandInt);
653 else
654 {
655 Deselect (event.m_commandInt);
656 return;
657 }
658 ProcessCommand (event);
659 }
660
661 void wxListBoxCallback (Widget w, XtPointer clientData,
662 XmListCallbackStruct * cbs)
663 {
664 /*
665 if (cbs->reason == XmCR_EXTENDED_SELECT)
666 cout << "*** Extend select\n";
667 else if (cbs->reason == XmCR_SINGLE_SELECT)
668 cout << "*** Single select\n";
669 else if (cbs->reason == XmCR_MULTIPLE_SELECT)
670 cout << "*** Multiple select\n";
671 else if (cbs->reason == XmCR_BROWSE_SELECT)
672 cout << "*** Browse select\n";
673
674 if (cbs->selection_type == XmMODIFICATION)
675 cout << "*** Modification\n";
676 else if (cbs->selection_type == XmINITIAL)
677 cout << "*** Initial\n";
678 else if (cbs->selection_type == XmADDITION)
679 cout << "*** Addition\n";
680 */
681
682 wxListBox *item = (wxListBox *) clientData;
683
684 if (item->m_inSetValue)
685 return;
686
687 wxCommandEvent event (wxEVT_COMMAND_LISTBOX_SELECTED);
688 switch (cbs->reason)
689 {
690 case XmCR_MULTIPLE_SELECT:
691 case XmCR_BROWSE_SELECT:
692 {
693 event.m_clientData = item->GetClientData (cbs->item_position - 1);
694 //event.commandString = item->GetStringSelection();
695 event.m_commandInt = cbs->item_position - 1;
696 event.m_extraLong = TRUE;
697 event.SetEventObject(item);
698 item->ProcessCommand (event);
699 //delete[] event.commandString; // Let's not store the command string any more
700 break;
701 }
702 case XmCR_EXTENDED_SELECT:
703 {
704 switch (cbs->selection_type)
705 {
706 case XmINITIAL:
707 case XmADDITION:
708 case XmMODIFICATION:
709 {
710 event.m_clientData = item->GetClientData (cbs->item_position - 1);
711 event.m_commandInt = cbs->item_position - 1;
712 event.m_extraLong = TRUE;
713 event.SetEventObject(item);
714 item->ProcessCommand (event);
715 break;
716 }
717 }
718 break;
719 }
720 }
721 }
722
723 /* Respond by getting the
724 * designated "default button" in the action area and activate it
725 * as if the user had selected it.
726 */
727 void wxListBoxDefaultActionProc (Widget list_w, XtPointer client_data, XmListCallbackStruct * cbs)
728 {
729 wxListBox *lbox = (wxListBox *) client_data;
730
731 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, lbox->GetId());
732 event.SetEventObject( lbox );
733 lbox->GetEventHandler()->ProcessEvent(event) ;
734 }
735
736 WXWidget wxListBox::GetTopWidget() const
737 {
738 return (WXWidget) XtParent( (Widget) m_mainWidget );
739 }