]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/motif/listbox.cpp
More Motif additions: mdi and sashtest samples now just about work!
[wxWidgets.git] / src / motif / listbox.cpp
... / ...
CommitLineData
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
29void wxListBoxCallback (Widget w, XtPointer clientData,
30 XmListCallbackStruct * cbs);
31
32void wxListBoxDefaultActionProc (Widget list_w, XtPointer client_data, XmListCallbackStruct * cbs);
33
34// ============================================================================
35// list box control implementation
36// ============================================================================
37
38// Listbox item
39wxListBox::wxListBox(): m_clientDataList(wxKEY_INTEGER)
40{
41 m_noItems = 0;
42 m_selected = 0;
43}
44
45bool wxListBox::Create(wxWindow *parent, wxWindowID id,
46 const wxPoint& pos,
47 const wxSize& size,
48 int n, const wxString choices[],
49 long style,
50 const wxValidator& validator,
51 const wxString& name)
52{
53 m_windowStyle = style;
54 m_noItems = n;
55 m_selected = 0;
56
57 SetName(name);
58 SetValidator(validator);
59
60 if (parent) parent->AddChild(this);
61
62 m_windowId = ( id == -1 ) ? (int)NewControlId() : id;
63
64 Widget parentWidget = (Widget) parent->GetClientWidget();
65
66 Arg args[3];
67 int count;
68 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
69 if (m_windowStyle & wxLB_MULTIPLE)
70 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
71 else if (m_windowStyle & wxLB_EXTENDED)
72 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
73 else
74 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
75 if (m_windowStyle & wxLB_ALWAYS_SB)
76 {
77 XtSetArg (args[2], XmNscrollBarDisplayPolicy, XmSTATIC);
78 count = 3;
79 }
80 else
81 count = 2;
82
83 Widget listWidget = XmCreateScrolledList (parentWidget, (char*) (const char*) name, args, count);
84
85 m_mainWidget = (WXWidget) listWidget;
86
87 Set(n, choices);
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
119wxListBox::~wxListBox()
120{
121}
122
123void 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
138void wxListBox::SetFirstItem(const wxString& s)
139{
140 int N = FindString (s);
141
142 if (N >= 0)
143 SetFirstItem (N);
144}
145
146void 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
181void 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
222void 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
268void 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
326int 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
344void 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
366void 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
401bool 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
418void wxListBox::Deselect(int N)
419{
420 XmListDeselectPos ((Widget) m_mainWidget, N + 1);
421}
422
423char *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
432void 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 else
438 node = m_clientDataList.Append((long) N, (wxObject*) Client_data);
439}
440
441// Return number of selections and an array of selected integers
442int wxListBox::GetSelections(wxArrayInt& aSelections) const
443{
444 aSelections.Empty();
445
446 Widget listBox = (Widget) m_mainWidget;
447 int *posList = NULL;
448 int posCnt = 0;
449 bool flag = XmListGetSelectedPos (listBox, &posList, &posCnt);
450 if (flag)
451 {
452 if (posCnt > 0)
453 {
454 aSelections.Alloc(posCnt);
455
456 int i;
457 for (i = 0; i < posCnt; i++)
458 aSelections.Add(posList[i] - 1);
459
460 XtFree ((char *) posList);
461 return posCnt;
462 }
463 else
464 return 0;
465 }
466 else
467 return 0;
468}
469
470// Get single selection, for single choice list items
471int wxListBox::GetSelection() const
472{
473 Widget listBox = (Widget) m_mainWidget;
474 int *posList = NULL;
475 int posCnt = 0;
476 bool flag = XmListGetSelectedPos (listBox, &posList, &posCnt);
477 if (flag)
478 {
479 int id = -1;
480 if (posCnt > 0)
481 id = posList[0] - 1;
482 XtFree ((char *) posList);
483 return id;
484 }
485 else
486 return -1;
487}
488
489// Find string for position
490wxString wxListBox::GetString(int N) const
491{
492 Widget listBox = (Widget) m_mainWidget;
493 XmString *strlist;
494 int n;
495 XtVaGetValues (listBox, XmNitemCount, &n, XmNitems, &strlist, NULL);
496 if (N <= n && N >= 0)
497 {
498 char *txt;
499 if (XmStringGetLtoR (strlist[N], XmSTRING_DEFAULT_CHARSET, &txt))
500 {
501 wxString str(txt);
502 XtFree (txt);
503 return str;
504 }
505 else
506 return wxEmptyString;
507 }
508 else
509 return wxEmptyString;
510}
511
512void wxListBox::SetSize(int x, int y, int width, int height, int sizeFlags)
513{
514 wxWindow::SetSize(x, y, width, height, sizeFlags);
515
516 // Check resulting size is correct
517 int tempW, tempH;
518 GetSize (&tempW, &tempH);
519
520 /*
521 if (tempW != width || tempH != height)
522 {
523 cout << "wxListBox::SetSize sizes not set correctly.");
524 }
525 */
526}
527
528void wxListBox::InsertItems(int nItems, const wxString items[], int pos)
529{
530 int width1, height1;
531 int width2, height2;
532
533 Widget listBox = (Widget) m_mainWidget;
534
535 GetSize(&width1, &height1);
536
537 bool managed = XtIsManaged(listBox);
538
539 if (managed)
540 XtUnmanageChild(listBox);
541
542 XmString *text = new XmString[nItems];
543 int i;
544 // Steve Hammes: Motif 1.1 compatibility
545// #if XmVersion > 1100
546// Corrected by Sergey Krasnov from Steve Hammes' code
547#if XmVersion > 1001
548 for (i = 0; i < nItems; i++)
549 text[i] = XmStringCreateSimple((char*) (const char*) items[i]);
550 XmListAddItemsUnselected(listBox, text, nItems, pos+1);
551#else
552 for (i = 0; i < nItems; i++)
553 {
554 text[i] = XmStringCreateSimple((char*) (const char*) items[i]);
555// XmListAddItemUnselected(listBox, text[i], i);
556 XmListAddItemUnselected(listBox, text[i], pos+i+1); // Another Sergey correction
557 }
558#endif
559 for (i = 0; i < nItems; i++)
560 XmStringFree(text[i]);
561
562 delete[] text;
563
564 // It seems that if the list is cleared, we must re-ask for
565 // selection policy!!
566 Arg args[3];
567 XtSetArg(args[0], XmNlistSizePolicy, XmCONSTANT);
568 if (m_windowStyle & wxLB_MULTIPLE)
569 XtSetArg(args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
570 else if (m_windowStyle & wxLB_EXTENDED)
571 XtSetArg(args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
572 else XtSetArg(args[1], XmNselectionPolicy, XmBROWSE_SELECT);
573 XtSetValues(listBox,args,2) ;
574
575 if (managed)
576 XtManageChild(listBox);
577
578 GetSize(&width2, &height2);
579 // Correct for randomly resized listbox - bad boy, Motif!
580 if (width1 != width2 /*|| height1 != height2*/)
581 SetSize(-1, -1, width1, height1);
582
583 m_noItems += nItems;
584}
585
586void wxListBox::SetString(int N, const wxString& s)
587{
588 int width1, height1;
589 int width2, height2;
590
591 Widget listBox = (Widget) m_mainWidget;
592 GetSize (&width1, &height1);
593
594 XmString text = XmStringCreateSimple ((char*) (const char*) s);
595
596 // WHAT'S THE MOTIF CALL TO SET THE TEXT OF AN EXISTING
597 // ITEM???
598 // There isn't one, so delete the item and add it again.
599 XmListDeletePos (listBox, N+1);
600 XmListAddItem (listBox, text, N+1);
601
602 XmStringFree(text);
603
604/*
605 // It seems that if the list is cleared, we must re-ask for
606 // selection policy!!
607 Arg args[3];
608 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
609 if (m_windowStyle & wxLB_MULTIPLE)
610 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
611 else if (m_windowStyle & wxLB_EXTENDED)
612 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
613 else
614 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
615 XtSetValues (listBox, args, 2);
616*/
617
618 GetSize (&width2, &height2);
619 // Correct for randomly resized listbox - bad boy, Motif!
620 if (width1 != width2 || height1 != height2)
621 SetSize (-1, -1, width1, height1);
622}
623
624int wxListBox::Number () const
625{
626 return m_noItems;
627}
628
629// For single selection items only
630wxString wxListBox::GetStringSelection () const
631{
632 int sel = GetSelection ();
633 if (sel > -1)
634 return this->GetString (sel);
635 else
636 return wxString("");
637}
638
639bool wxListBox::SetStringSelection (const wxString& s, bool flag)
640{
641 int sel = FindString (s);
642 if (sel > -1)
643 {
644 SetSelection (sel, flag);
645 return TRUE;
646 }
647 else
648 return FALSE;
649}
650
651void wxListBox::Command (wxCommandEvent & event)
652{
653 if (event.m_extraLong)
654 SetSelection (event.m_commandInt);
655 else
656 {
657 Deselect (event.m_commandInt);
658 return;
659 }
660 ProcessCommand (event);
661}
662
663void wxListBoxCallback (Widget w, XtPointer clientData,
664 XmListCallbackStruct * cbs)
665{
666/*
667 if (cbs->reason == XmCR_EXTENDED_SELECT)
668 cout << "*** Extend select\n";
669 else if (cbs->reason == XmCR_SINGLE_SELECT)
670 cout << "*** Single select\n";
671 else if (cbs->reason == XmCR_MULTIPLE_SELECT)
672 cout << "*** Multiple select\n";
673 else if (cbs->reason == XmCR_BROWSE_SELECT)
674 cout << "*** Browse select\n";
675
676 if (cbs->selection_type == XmMODIFICATION)
677 cout << "*** Modification\n";
678 else if (cbs->selection_type == XmINITIAL)
679 cout << "*** Initial\n";
680 else if (cbs->selection_type == XmADDITION)
681 cout << "*** Addition\n";
682 */
683
684 wxListBox *item = (wxListBox *) clientData;
685
686 if (item->InSetValue())
687 return;
688
689 wxCommandEvent event (wxEVT_COMMAND_LISTBOX_SELECTED);
690 switch (cbs->reason)
691 {
692 case XmCR_MULTIPLE_SELECT:
693 case XmCR_BROWSE_SELECT:
694 {
695 event.m_clientData = item->GetClientData (cbs->item_position - 1);
696 //event.commandString = item->GetStringSelection();
697 event.m_commandInt = cbs->item_position - 1;
698 event.m_extraLong = TRUE;
699 event.SetEventObject(item);
700 item->ProcessCommand (event);
701 //delete[] event.commandString; // Let's not store the command string any more
702 break;
703 }
704 case XmCR_EXTENDED_SELECT:
705 {
706 switch (cbs->selection_type)
707 {
708 case XmINITIAL:
709 case XmADDITION:
710 case XmMODIFICATION:
711 {
712 event.m_clientData = item->GetClientData (cbs->item_position - 1);
713 event.m_commandInt = cbs->item_position - 1;
714 event.m_extraLong = TRUE;
715 event.SetEventObject(item);
716 item->ProcessCommand (event);
717 break;
718 }
719 }
720 break;
721 }
722 }
723}
724
725/* Respond by getting the
726 * designated "default button" in the action area and activate it
727 * as if the user had selected it.
728 */
729void wxListBoxDefaultActionProc (Widget list_w, XtPointer client_data, XmListCallbackStruct * cbs)
730{
731 wxListBox *lbox = (wxListBox *) client_data;
732
733 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, lbox->GetId());
734 event.SetEventObject( lbox );
735 lbox->GetEventHandler()->ProcessEvent(event) ;
736}
737
738WXWidget wxListBox::GetTopWidget() const
739{
740 return (WXWidget) XtParent( (Widget) m_mainWidget );
741}