]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/motif/listbox.cpp
Dialog unit mods; wxProp tidying
[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 m_inSetValue = FALSE;
44}
45
46bool 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
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}
438
439// Return number of selections and an array of selected integers
440int 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
469int 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
488wxString 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
510void 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
519void wxListBox::InsertItems(int nItems, const wxString items[], int pos)
520{
521 int width1, height1;
522 int width2, height2;
523
524 Widget listBox = (Widget) m_mainWidget;
525
526 GetSize(&width1, &height1);
527
528 bool managed = XtIsManaged(listBox);
529
530 if (managed)
531 XtUnmanageChild(listBox);
532
533 XmString *text = new XmString[nItems];
534 int i;
535 // Steve Hammes: Motif 1.1 compatibility
536// #if XmVersion > 1100
537// Corrected by Sergey Krasnov from Steve Hammes' code
538#if XmVersion > 1001
539 for (i = 0; i < nItems; i++)
540 text[i] = XmStringCreateSimple((char*) (const char*) items[i]);
541 XmListAddItemsUnselected(listBox, text, nItems, pos+1);
542#else
543 for (i = 0; i < nItems; i++)
544 {
545 text[i] = XmStringCreateSimple((char*) (const char*) items[i]);
546// XmListAddItemUnselected(listBox, text[i], i);
547 XmListAddItemUnselected(listBox, text[i], pos+i+1); // Another Sergey correction
548 }
549#endif
550 for (i = 0; i < nItems; i++)
551 XmStringFree(text[i]);
552
553 delete[] text;
554
555 // It seems that if the list is cleared, we must re-ask for
556 // selection policy!!
557 Arg args[3];
558 XtSetArg(args[0], XmNlistSizePolicy, XmCONSTANT);
559 if (m_windowStyle & wxLB_MULTIPLE)
560 XtSetArg(args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
561 else if (m_windowStyle & wxLB_EXTENDED)
562 XtSetArg(args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
563 else XtSetArg(args[1], XmNselectionPolicy, XmBROWSE_SELECT);
564 XtSetValues(listBox,args,2) ;
565
566 if (managed)
567 XtManageChild(listBox);
568
569 GetSize(&width2, &height2);
570 // Correct for randomly resized listbox - bad boy, Motif!
571 if (width1 != width2 /*|| height1 != height2*/)
572 SetSize(-1, -1, width1, height1);
573
574 m_noItems += nItems;
575}
576
577void wxListBox::SetString(int N, const wxString& s)
578{
579 int width1, height1;
580 int width2, height2;
581
582 Widget listBox = (Widget) m_mainWidget;
583 GetSize (&width1, &height1);
584
585 XmString text = XmStringCreateSimple ((char*) (const char*) s);
586
587 // WHAT'S THE MOTIF CALL TO SET THE TEXT OF AN EXISTING
588 // ITEM???
589 // There isn't one, so delete the item and add it again.
590 XmListDeletePos (listBox, N+1);
591 XmListAddItem (listBox, text, N+1);
592
593 XmStringFree(text);
594
595/*
596 // It seems that if the list is cleared, we must re-ask for
597 // selection policy!!
598 Arg args[3];
599 XtSetArg (args[0], XmNlistSizePolicy, XmCONSTANT);
600 if (m_windowStyle & wxLB_MULTIPLE)
601 XtSetArg (args[1], XmNselectionPolicy, XmMULTIPLE_SELECT);
602 else if (m_windowStyle & wxLB_EXTENDED)
603 XtSetArg (args[1], XmNselectionPolicy, XmEXTENDED_SELECT);
604 else
605 XtSetArg (args[1], XmNselectionPolicy, XmBROWSE_SELECT);
606 XtSetValues (listBox, args, 2);
607*/
608
609 GetSize (&width2, &height2);
610 // Correct for randomly resized listbox - bad boy, Motif!
611 if (width1 != width2 || height1 != height2)
612 SetSize (-1, -1, width1, height1);
613}
614
615int wxListBox::Number () const
616{
617 return m_noItems;
618}
619
620// For single selection items only
621wxString wxListBox::GetStringSelection () const
622{
623 int sel = GetSelection ();
624 if (sel > -1)
625 return this->GetString (sel);
626 else
627 return wxString("");
628}
629
630bool wxListBox::SetStringSelection (const wxString& s, bool flag)
631{
632 int sel = FindString (s);
633 if (sel > -1)
634 {
635 SetSelection (sel, flag);
636 return TRUE;
637 }
638 else
639 return FALSE;
640}
641
642void wxListBox::Command (wxCommandEvent & event)
643{
644 if (event.m_extraLong)
645 SetSelection (event.m_commandInt);
646 else
647 {
648 Deselect (event.m_commandInt);
649 return;
650 }
651 ProcessCommand (event);
652}
653
654void wxListBoxCallback (Widget w, XtPointer clientData,
655 XmListCallbackStruct * cbs)
656{
657/*
658 if (cbs->reason == XmCR_EXTENDED_SELECT)
659 cout << "*** Extend select\n";
660 else if (cbs->reason == XmCR_SINGLE_SELECT)
661 cout << "*** Single select\n";
662 else if (cbs->reason == XmCR_MULTIPLE_SELECT)
663 cout << "*** Multiple select\n";
664 else if (cbs->reason == XmCR_BROWSE_SELECT)
665 cout << "*** Browse select\n";
666
667 if (cbs->selection_type == XmMODIFICATION)
668 cout << "*** Modification\n";
669 else if (cbs->selection_type == XmINITIAL)
670 cout << "*** Initial\n";
671 else if (cbs->selection_type == XmADDITION)
672 cout << "*** Addition\n";
673 */
674
675 wxListBox *item = (wxListBox *) clientData;
676
677 if (item->m_inSetValue)
678 return;
679
680 wxCommandEvent event (wxEVT_COMMAND_LISTBOX_SELECTED);
681 switch (cbs->reason)
682 {
683 case XmCR_MULTIPLE_SELECT:
684 case XmCR_BROWSE_SELECT:
685 {
686 event.m_clientData = item->GetClientData (cbs->item_position - 1);
687 //event.commandString = item->GetStringSelection();
688 event.m_commandInt = cbs->item_position - 1;
689 event.m_extraLong = TRUE;
690 event.SetEventObject(item);
691 item->ProcessCommand (event);
692 //delete[] event.commandString; // Let's not store the command string any more
693 break;
694 }
695 case XmCR_EXTENDED_SELECT:
696 {
697 switch (cbs->selection_type)
698 {
699 case XmINITIAL:
700 case XmADDITION:
701 case XmMODIFICATION:
702 {
703 event.m_clientData = item->GetClientData (cbs->item_position - 1);
704 event.m_commandInt = cbs->item_position - 1;
705 event.m_extraLong = TRUE;
706 event.SetEventObject(item);
707 item->ProcessCommand (event);
708 break;
709 }
710 }
711 break;
712 }
713 }
714}
715
716/* Respond by getting the
717 * designated "default button" in the action area and activate it
718 * as if the user had selected it.
719 */
720void wxListBoxDefaultActionProc (Widget list_w, XtPointer client_data, XmListCallbackStruct * cbs)
721{
722 wxListBox *lbox = (wxListBox *) client_data;
723
724 wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, lbox->GetId());
725 event.SetEventObject( lbox );
726 lbox->GetEventHandler()->ProcessEvent(event) ;
727}
728
729