Initial revision
[ssr] / StraySrc / Libraries / Steel / c / listbox
1 /*
2 * ListBox
3 * Provides handling for list boxes
4 *
5 * v. 1.00 (27 July 1993)
6 *
7 * © 1993-1998 Straylight
8 */
9
10 /*----- Licensing note ----------------------------------------------------*
11 *
12 * This file is part of Straylight's Steel library.
13 *
14 * Steel is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
17 * any later version.
18 *
19 * Steel is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Steel. If not, write to the Free Software Foundation,
26 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "wimp.h"
34 #include "wimpt.h"
35 #include "event.h"
36 #include "win.h"
37 #include "template.h"
38 #include "listbox.h"
39 #include "werr.h"
40 #include "msgs.h"
41 #include "bbc.h"
42 #include "mem.h"
43 #include "utils.h"
44 #include "help.h"
45 #include "visdelay.h"
46 #include "dll.h"
47
48 #ifndef _dll_NODLL
49 extern void _dllEntry(list__events)(wimp_eventstr *e,void *handle);
50 #endif
51
52 #define list__ITEMHEIGHT 44
53 #define list__MINHEIGHT 176
54
55 /*
56 * A structure for the list items
57 */
58 typedef struct list__item
59 {
60 struct list__item *next;
61 struct list__item *prev;
62 void *handle;
63 char *data;
64 BOOL selected :1;
65 BOOL nsel :1;
66 }
67 list__item;
68
69 /*
70 * A structure that says everything about a listbox
71 */
72 typedef struct list__liststr
73 {
74 wimp_w wind;
75 wimp_box visSize;
76 wimp_wind *windDef;
77 int foreg;
78 int backg;
79 list_eventhandler events;
80 void *evntHandle;
81 list_raweventhandler rawEvents;
82 void *rawHandle;
83 list_redrawhandler rdr;
84 void *redrawHandle;
85 int items;
86 int width;
87 list_item selected;
88 list_item list;
89 int nsel;
90 pane p;
91 int iHeight;
92 int extWidth;
93 int extraWidth;
94 BOOL alterSize :1;
95 BOOL multSel :1;
96 BOOL update :1;
97 }
98 list__liststr;
99
100 static list list__dragging;
101 static int list__dragIndex;
102 static int list__currentIndex;
103
104 _dll_static void list__events(wimp_eventstr *e,void *handle);
105
106 /*
107 * void list__resize(list l)
108 *
109 * Use
110 * This routine will resize a list box according to how many items there
111 * are in it.
112 *
113 * Parameters
114 * list l == the list handle
115 */
116
117 static void list__resize(list l)
118 {
119 wimp_wstate s;
120 int height;
121 int width;
122 BOOL open;
123 int maxlen;
124 wimp_redrawstr extent;
125 wimp_box b;
126 BOOL hscr=FALSE,ohscr;
127 BOOL vscr=FALSE,ovscr;
128 wimp_winfo w;
129 menu_handler mhnd;
130 pane p=0;
131 int xe=0,ye=0;
132 int scbh=0;
133
134 /* --- Find out if there's anything to do --- */
135
136 if (!l->wind || !l->update)
137 return;
138
139 /* --- Get information about the window --- */
140
141 wimpt_noerr(wimp_get_wind_state(l->wind,&s));
142 open=s.flags & wimp_WOPEN;
143 height=l->items*l->iHeight;
144 width=maxlen=l->width+16+l->extraWidth;
145
146 /* --- If it's a pane listbox, add in scroll bars if necessary --- */
147
148 if (!l->alterSize)
149 {
150 /* --- First, read the position and scroll sizes --- */
151
152 win_gadgetWidths(wimp_WNEW | wimp_WVSCR | wimp_WHSCR,&b);
153
154 /* --- Get the outline extents of the window --- */
155
156 ohscr=s.flags & wimp_WHSCR;
157 ovscr=s.flags & wimp_WVSCR;
158 scbh=b.y0-wimpt_dy();
159 xe=s.o.box.x1-s.o.box.x0+(ovscr ? b.x1-wimpt_dx() : 0);
160 ye=s.o.box.y1-s.o.box.y0+(ohscr ? scbh : 0);
161
162 /* --- Now find out if we really want scroll bars --- */
163
164 if (maxlen>xe)
165 {
166 hscr=TRUE;
167 ye-=b.y0-wimpt_dy();
168 }
169
170 if (height>ye)
171 {
172 vscr=TRUE;
173 xe-=b.x1-wimpt_dx();
174 }
175
176 if (!hscr && maxlen>xe)
177 {
178 hscr=TRUE;
179 ye-=b.y0-wimpt_dy();
180 }
181
182 /* --- If we changed the scroll bars, recreate the window --- */
183
184 if (!hscr!=!ohscr || !vscr!=!ovscr)
185 {
186 /* --- Update the scroll bar flags --- */
187
188 ohscr=hscr;
189 ovscr=vscr;
190
191 /* --- Save all the window's info so we recreate it properly --- */
192
193 if (l->p)
194 {
195 p=l->p;
196 pane_removePane(p,l->wind);
197 }
198 w.w=l->wind;
199 wimpt_noerr(wimp_get_wind_info(&w));
200 menu_saveHandler(l->wind,&mhnd);
201 wimpt_noerr(wimp_delete_wind(l->wind));
202 win_register_event_handler(l->wind,0,0);
203
204 /* --- Set up window with new scroll bar gadgetry --- */
205
206 w.info.flags&=~(wimp_WHSCR | wimp_WVSCR);
207 if (hscr)
208 w.info.flags|=wimp_WHSCR;
209 if (vscr)
210 w.info.flags|=wimp_WVSCR;
211 w.info.flags|=wimp_WNEW;
212 w.info.ex.x1+=200;
213 w.info.ex.y0-=200;
214 wimpt_noerr(wimp_create_wind(&w.info,&l->wind));
215
216 /* --- Read the new outline and check the sizes again --- */
217
218 s.o.w=l->wind;
219 s.o.box.x1=s.o.box.x0+xe;
220 s.o.box.y0=s.o.box.y1-ye;
221 wimpt_noerr(wimp_open_wind(&s.o));
222
223 /* --- Restore everything we saved above --- */
224
225 if (!open)
226 wimpt_noerr(wimp_close_wind(l->wind));
227 win_register_event_handler(l->wind,_dllEntry(list__events),l);
228 menu_restoreHandler(l->wind,&mhnd);
229 }
230 }
231 else
232 xe=l->visSize.x1-l->visSize.x0;
233
234 /* --- Correct the extent dimensions --- */
235
236 if (width<xe)
237 width=xe;
238 if (height<ye && !l->alterSize)
239 height=ye;
240 if (height<list__MINHEIGHT-scbh)
241 height=list__MINHEIGHT-scbh;
242
243 extent.w=l->wind;
244 extent.box.x0=l->visSize.x0;
245 extent.box.x1=l->visSize.x0+width;
246 extent.box.y0=-height;
247 extent.box.y1=0;
248 l->extWidth=width; /* Remember the width of the window for redrawing */
249 wimpt_noerr(wimp_set_extent(&extent));
250 if (open)
251 {
252 wimpt_noerr(wimp_open_wind(&s.o));
253 wimpt_noerr(wimp_force_redraw(&extent));
254 }
255 if (p)
256 {
257 l->p=p;
258 pane_addListbox(p,l);
259 }
260 }
261
262 /*
263 * void list__rescanSize(list l)
264 *
265 * Use
266 * Recalculates a list box's width.
267 */
268
269 static void list__rescanSize(list l)
270 {
271 list_item itm;
272 int len;
273
274 if (!l->wind || !l->update)
275 return;
276
277 l->width=0;
278 itm=l->list;
279 while (itm)
280 {
281 len=wimpt_stringWidth(itm->data);
282 if (len>l->width)
283 l->width=len;
284 itm=itm->next;
285 }
286 list__resize(l);
287 }
288
289 /*
290 * void list__event(list l,list_item clicked)
291 *
292 * Use
293 * Posts an event to the event handler registered for the list box (if it's
294 * there).
295 *
296 * Parameters
297 * list l == the list box handle
298 * list_item clicked == the item that was clicked
299 */
300
301 static void list__event(list l,list_item clicked)
302 {
303 if (l->events)
304 (l->events)(l,clicked,l->evntHandle);
305 }
306
307 /*
308 * void list__defaultRedraw(list l,
309 * wimp_box *b,
310 * char *text,
311 * BOOL selected)
312 *
313 * Use
314 * Standard redraw handler for list boxes. This may be overridden if the
315 * list box is a fancy one.
316 *
317 * Parameters
318 * As for list redraw handlers, except that there's no handle passed to it.
319 */
320
321 static void list__defaultRedraw(list l,
322 wimp_box *b,
323 char *text,
324 BOOL selected)
325 {
326 wimp_icon icn;
327 icn.box=*b;
328 icn.flags=0x00000131+(l->foreg<<24)+(l->backg<<28);
329 icn.data.indirecttext.validstring=(char *)-1;
330 icn.data.indirecttext.bufflen=0;
331 if (selected)
332 icn.flags|=wimp_ISELECTED;
333 else
334 icn.flags&=~wimp_ISELECTED;
335 icn.data.indirecttext.buffer=text;
336 wimpt_noerr(wimp_ploticon(&icn));
337 }
338
339 /*
340 * void list__redraw(wimp_redrawstr *r,void *handle)
341 *
342 * Use
343 * Redraws a list box window
344 *
345 * Parameters
346 * wimp_redrawstr *r == redraw structure for this redraw event
347 * void *handle == pointer to this list box
348 */
349
350 static void list__redraw(wimp_redrawstr *r,void *handle)
351 {
352 list l=(list)handle;
353 list_item itm=l->list;
354 int ox=r->box.x0-r->scx;
355 int oy=r->box.y1-r->scy;
356 int i=0;
357 int first=-(r->g.y1-r->box.y1+r->scy)/l->iHeight;
358 int last=first+(r->g.y1-r->g.y0)/l->iHeight+1;
359 wimp_box box;
360 box.x0=l->visSize.x0;
361 box.x1=l->visSize.x0+l->extWidth;
362 box.y1=0;
363 box.y0=-l->iHeight;
364 while (itm)
365 {
366 if (i>=first && i<=last)
367 {
368 if (l->rdr)
369 {
370 (l->rdr)(l,itm,r,&box,itm->data,
371 itm->selected || itm->nsel,l->redrawHandle);
372 }
373 else
374 list__defaultRedraw(l,&box,itm->data,itm->selected || itm->nsel);
375 }
376 itm=itm->next;
377 box.y0-=l->iHeight;
378 box.y1-=l->iHeight;
379 i++;
380 }
381 wimpt_noerr(wimp_setcolour(l->backg));
382 if (i<=last)
383 {
384 bbc_rectanglefill(l->visSize.x0+ox,
385 box.y1+oy-l->iHeight*(last-i+1)-wimpt_dy(),
386 l->extWidth,
387 l->iHeight*(last-i+1));
388 }
389 }
390
391 /*
392 * list_item list__coordsToItem(int x,int y,list l)
393 *
394 * Use
395 * Given a screen position and a list handle, returns
396 * the item beneath the point.
397 *
398 * Parameters
399 * int x == absolute OS-unit screen x-coordinate of the point
400 * int y == absolute OS-unit screen y-coordinate of the point
401 * list l == the list handle
402 *
403 * Returns
404 * The list item handle
405 */
406
407 static list_item list__coordsToItem(int x,int y,list l)
408 {
409 wimp_wstate state;
410 int oy;
411 list_item i;
412 int index;
413 x=x;
414 wimpt_noerr(wimp_get_wind_state(l->wind,&state));
415 oy=state.o.box.y1-state.o.y;
416 index=-(y-oy+wimpt_dy())/l->iHeight;
417 if (index>=l->items)
418 return (list_NOITEM);
419 i=list_indexToItem(l,index);
420 return (i);
421 }
422
423 /*
424 * void list__selectIdles(void *handle)
425 *
426 * Use
427 * Gets passed idle events when dragging out a selection.
428 *
429 * Parameters
430 * void *handle == a NULL pointer
431 */
432
433 #define min2(x,y) ((x)<(y) ? (x) : (y))
434 #define max2(x,y) ((x)>(y) ? (x) : (y))
435 #define min3(x,y,z) min2(min2(x,y),z)
436 #define max3(x,y,z) max2(max2(x,y),z)
437
438 static void list__redrawItem(list l,int i);
439
440 static void list__selectIdles(void *handle)
441 {
442 /* --- Rewritten 24-Jun-1993 - MDW --- */
443
444 /* --- Variables required to update the drag --- */
445 wimp_mousestr m; /* Pointer state (window coords) */
446 wimp_wstate s; /* Position of window */
447 int ox,oy; /* Screen coords of window origin */
448 int i; /* Item index counter */
449 int start; /* Index to start processing items */
450 int end; /* Index to finish processing items */
451 int index; /* Index of item under pointer */
452 list_item item; /* List item ptr (for list traverse) */
453 int sel; /* -1 == ignore, 0 == deselect, */
454 /* 1 == select */
455
456 handle=handle;
457
458 /* --- Set up pointer position --- */
459 wimpt_noerr(wimp_get_point_info(&m)); /* I only need the coordinates */
460 wimpt_noerr(wimp_get_wind_state(list__dragging->wind,&s)); /* For origin,*/
461 /* and scrolling the window */
462 ox=s.o.box.x0-s.o.x; /* Derive position of window origin */
463 oy=s.o.box.y1-s.o.y; /* from state as per PRM */
464 m.x-=ox; /* Now convert mouse position to */
465 m.y-=oy; /* window coordinates */
466 index=-(m.y+wimpt_dy())/list__dragging->iHeight; /* Calc item under ptr */
467 if (index<0) /* Stop negative indices */
468 index=0;
469
470 /* --- Set up for loop through list items --- */
471 start=min3(list__currentIndex,list__dragIndex,index);
472 end=max3(list__currentIndex,list__dragIndex,index);
473 item=list__dragging->list;
474 i=0;
475 sel=-1;
476
477 /* --- Now loop through the relevant icons --- */
478 while (item) /* Carry on until we run out of items*/
479 {
480 if (i==start)
481 sel=0;
482 if (list__dragIndex<index)
483 {
484 if (i==list__dragIndex)
485 sel=TRUE;
486 if (i==index+1)
487 sel=FALSE;
488 }
489 else
490 {
491 if (i==index)
492 sel=TRUE;
493 if (i==list__dragIndex+1)
494 sel=FALSE;
495 }
496 if (i==end+1)
497 sel=-1;
498 if (sel!=-1 && !item->selected && sel!=item->nsel)
499 {
500 item->nsel=sel;
501 list__redrawItem(list__dragging,i);
502 list__dragging->nsel+=(sel==TRUE)-(sel==FALSE);
503 }
504 i++;
505 item=item->next;
506 }
507 list__currentIndex=index;
508
509 /* --- Scroll the window to include the added selection --- */
510 if (m.y>s.o.y) /* If pointer too far up, scroll up */
511 s.o.y=m.y;
512 else if (m.y+s.o.box.y1-s.o.box.y0<s.o.y) /* If too far down, scroll down*/
513 s.o.y=m.y+s.o.box.y1-s.o.box.y0;
514 wimpt_noerr(wimp_open_wind(&s.o)); /* Open the window in new position */
515 }
516
517 /*
518 * BOOL list__selectUnknowns(wimp_eventstr *e,void *handle)
519 *
520 * Use
521 * Unknown event handler for dragging out selections.
522 *
523 * Parameters
524 * wimp_eventstr *e == the unknown event
525 * void *handle == a NULL pointer
526 *
527 * Returns
528 * TRUE if the event was interesting
529 */
530
531 static BOOL list__selectUnknowns(wimp_eventstr *e,void *handle)
532 {
533 BOOL handled=FALSE;
534 list_item i;
535 handle=handle;
536 switch (e->e)
537 {
538 case wimp_EUSERDRAG:
539 list__selectIdles(0);
540 for (i=list__dragging->list;i;i=i->next)
541 {
542 if (i->nsel)
543 i->selected=TRUE;
544 i->nsel=FALSE;
545 }
546 win_remove_unknown_event_processor(list__selectUnknowns,0);
547 win_remove_idle_claimer(list__selectIdles,0);
548 handled=TRUE;
549 break;
550 }
551 return (handled);
552 }
553
554 /*
555 * BOOL list__modeChange(wimp_eventstr *e,void *handle)
556 *
557 * Use
558 * Handles mode change events for list boxes (rescan the width)
559 */
560
561 static BOOL list__modeChange(wimp_eventstr *e,void *handle)
562 {
563 list l=handle;
564
565 switch (e->e)
566 {
567 case wimp_ESEND:
568 case wimp_ESENDWANTACK:
569 if (e->data.msg.hdr.action==wimp_MMODECHANGE ||
570 e->data.msg.hdr.action==0x400CF)
571 list__rescanSize(l);
572 break;
573 }
574 return (FALSE);
575 }
576
577 /*
578 * void list__events(wimp_eventstr *e,void *handle)
579 *
580 * Use
581 * The event handler for list boxes.
582 *
583 * Parameters
584 * wimp_eventstr *e == the event
585 * void *handle == the list box handle
586 */
587
588 _dll_static void list__events(wimp_eventstr *e,void *handle)
589 {
590 list l=(list)handle;
591 BOOL handled=FALSE;
592 if (l->rawEvents)
593 handled=(l->rawEvents)(l,e,l->rawHandle);
594 if (!handled)
595 {
596 switch (e->e)
597 {
598 case wimp_EREDRAW:
599 wimpt_redraw(list__redraw,l);
600 break;
601 case wimp_EOPEN:
602 wimpt_noerr(wimp_open_wind(&e->data.o));
603 break;
604 case wimp_ECLOSE:
605 list__event(l,list_CLOSE);
606 break;
607 case wimp_EBUT:
608 if
609 (
610 e->data.but.m.bbits & wimp_BLEFT ||
611 e->data.but.m.bbits & wimp_BRIGHT ||
612 e->data.but.m.bbits & wimp_BCLICKLEFT ||
613 e->data.but.m.bbits & wimp_BCLICKRIGHT
614 )
615 {
616 list_item i=list__coordsToItem(e->data.but.m.x,e->data.but.m.y,l);
617 if (e->data.but.m.bbits&wimp_BLEFT || l->multSel==FALSE)
618 list_selectItem(l,i);
619 else
620 list_addToSelection(l,i,list_TOGGLESTATE);
621 list__event(l,l->selected);
622 }
623 else if
624 (
625 (e->data.but.m.bbits & wimp_BDRAGLEFT ||
626 e->data.but.m.bbits & wimp_BDRAGRIGHT) &&
627 l->multSel==TRUE
628 )
629 {
630 wimp_dragstr d;
631 wimp_wstate s;
632 wimpt_noerr(wimp_get_wind_state(l->wind,&s));
633 d.type=wimp_USER_HIDDEN;
634 d.parent.x0=e->data.but.m.x;
635 d.parent.y0=0x9001;
636 d.parent.x1=e->data.but.m.x;
637 d.parent.y1=0x6FFE;
638 wimpt_noerr(wimp_drag_box(&d));
639 list__dragging=l;
640 list__dragIndex=-(e->data.but.m.y+wimpt_dy()-s.o.box.y1+s.o.y)/
641 l->iHeight;
642 list__currentIndex=list__dragIndex;
643 list__selectIdles(0);
644 win_add_unknown_event_processor(list__selectUnknowns,0);
645 win_addIdleClaimer(list__selectIdles,2,0);
646 }
647 break;
648 case wimp_EKEY:
649 wimpt_noerr(wimp_processkey(e->data.key.chcode));
650 break;
651 case wimp_ESCROLL:
652 {
653 int height=e->data.scroll.o.box.y1-e->data.scroll.o.box.y0;
654 int width=e->data.scroll.o.box.x1-e->data.scroll.o.box.x0;
655 switch (e->data.scroll.y)
656 {
657 case -2:
658 {
659 int bottom=-(e->data.scroll.o.y-height)/l->iHeight;
660 int itms=height/l->iHeight;
661 if (-bottom*l->iHeight==e->data.scroll.o.y-height)
662 bottom--;
663 e->data.scroll.o.y=-(bottom+itms)*l->iHeight+height;
664 }
665 break;
666 case -1:
667 {
668 int bottom=-(e->data.scroll.o.y-height)/l->iHeight;
669 bottom++;
670 e->data.scroll.o.y=-bottom*l->iHeight+height;
671 }
672 break;
673 case 0:
674 break;
675 case 1:
676 {
677 int top=-(e->data.scroll.o.y)/l->iHeight;
678 if (-top*l->iHeight==e->data.scroll.o.y)
679 top--;
680 e->data.scroll.o.y=-top*l->iHeight;
681 }
682 break;
683 case 2:
684 {
685 int top=-(e->data.scroll.o.y)/l->iHeight;
686 int itms=height/l->iHeight;
687 if (-top*l->iHeight!=e->data.scroll.o.y);
688 top++;
689 e->data.scroll.o.y=-(top-itms)*l->iHeight;
690 }
691 break;
692 }
693 switch (e->data.scroll.x)
694 {
695 case -2:
696 e->data.scroll.o.x-=width;
697 break;
698 case -1:
699 e->data.scroll.o.x-=32;
700 break;
701 case 0:
702 break;
703 case 1:
704 e->data.scroll.o.x+=32;
705 break;
706 case 2:
707 e->data.scroll.o.x+=width;
708 break;
709 }
710 wimpt_noerr(wimp_open_wind(&(e->data.scroll.o)));
711 }
712 break;
713 case wimp_ESEND:
714 case wimp_ESENDWANTACK:
715 switch (e->data.msg.hdr.action)
716 {
717 case wimp_MHELPREQUEST:
718 list__event(l,list_HELP);
719 break;
720 }
721 break;
722 }
723 }
724 }
725
726 /*
727 * list_item list__findItem(list l,list_item i)
728 *
729 * Use
730 * Returns a pointer to a list item.
731 *
732 * Parameters
733 * list l == the list
734 * list_item i == the item number
735 *
736 * Returns
737 * A pointer to the list item or 0 if it couldn't be found.
738 */
739
740 #define list__findItem(l,i) (i)
741
742 /*
743 * void list_isPane(list l,pane p)
744 *
745 * Use
746 * This routine is part of the private interface between the listbox and
747 * pane segments. Do *NOT* try to call it in your own code.
748 */
749
750 void list_isPane(list l,pane p)
751 {
752 l->p=p;
753 if (l->p!=p && p)
754 list__resize(l);
755 }
756
757 /*
758 * void list__redrawItem(list l,int item)
759 *
760 * Use
761 * Calls for a redraw of a single list item
762 *
763 * Parameters
764 * list l == the list handle
765 * int i == the item index
766 */
767
768 static void list__redrawItem(list l,int i)
769 {
770 wimp_redrawstr r;
771 wimp_wstate s;
772 BOOL more;
773 if (i!=-1)
774 {
775 wimpt_noerr(wimp_get_wind_state(l->wind,&s));
776 r.w=l->wind;
777 r.box.x0=s.o.x;
778 r.box.x1=s.o.x+s.o.box.x1-s.o.box.x0;
779 r.box.y0=-l->iHeight*i-l->iHeight;
780 r.box.y1=-l->iHeight*i;
781 wimpt_noerr(wimp_update_wind(&r,&more));
782 while (more)
783 {
784 list__redraw(&r,l);
785 wimpt_noerr(wimp_get_rectangle(&r,&more));
786 }
787 }
788 }
789
790 /*
791 * void list_selectItem(list l,list_item item)
792 *
793 * Use
794 * Makes the item the currently selected one.
795 *
796 * Parameters
797 * list l == the list handle
798 * list_item item == the item number
799 */
800
801 void list_selectItem(list l,list_item item)
802 {
803 list_item i=l->list;
804 int c=0;
805 visdelay_begin();
806 while (i)
807 {
808 if (i->selected==TRUE && i!=item)
809 {
810 i->selected=FALSE;
811 list__redrawItem(l,c);
812 l->nsel--;
813 }
814 c++;
815 i=i->next;
816 }
817 visdelay_end();
818 l->selected=list_NOITEM;
819 list_addToSelection(l,item,list_SETSTATE);
820 }
821
822 /*
823 * list_item list_selected(list l)
824 *
825 * Use
826 * Returns the currently selected item of the list.
827 *
828 * Parameters
829 * list l == the list handle
830 *
831 * Returns
832 * The item number of the currently selected item.
833 */
834
835 list_item list_selected(list l)
836 {
837 list_item itm=l->list;
838 while (itm)
839 {
840 if (itm->selected)
841 return (itm);
842 itm=itm->next;
843 }
844 return (list_NOITEM);
845 }
846
847 /*
848 * list list_create(char *name,BOOL alterSize)
849 *
850 * Use
851 * Creates a new list box window, and returns a handle to it. Initially,
852 * there are no items, and the list box is not shown. The function returns
853 * 0 if the call fails for one reason or another (not enough windows or
854 * memory).
855 *
856 * Parameters
857 * char *name == the name to match in the template file
858 * BOOL alterSize == TRUE if we are allowed to change the box's visible
859 * size.
860 *
861 * Returns
862 * An abstract handle for the list box.
863 */
864
865 list list_create(char *name,BOOL alterSize)
866 {
867 list new=(list)mem_alloc(sizeof(list__liststr));
868 if (new==0)
869 {
870 werr(FALSE,msgs_lookup("listNEM:Not enough room to create list box."));
871 return (0);
872 }
873
874 win_activeinc();
875 new->events=0;
876 new->rawEvents=0;
877 new->items=0;
878 new->width=0;
879 new->list=0;
880 new->selected=list_NOITEM;
881 new->windDef=template_syshandle(name);
882 new->alterSize=alterSize;
883 new->wind=0;
884 new->foreg=new->windDef->colours[wimp_WCWKAREAFORE];
885 new->backg=new->windDef->colours[wimp_WCWKAREABACK];
886 new->multSel=FALSE;
887 new->nsel=0;
888 new->p=0;
889 new->rdr=0;
890 new->extraWidth=0;
891 new->iHeight=list__ITEMHEIGHT;
892 return (new);
893 }
894
895 /*
896 * char *list_itemData(list l,list_item i)
897 *
898 * Use
899 * Returns the string for an item
900 *
901 * Parameters
902 * list l == the list handle
903 * list_item i == the item's handle
904 *
905 * Returns
906 * A pointer to the item's data
907 */
908
909 char *list_itemData(list l,list_item i)
910 {
911 l=l;
912 return (list__findItem(l,i)->data);
913 }
914
915 /*
916 * list_item list_addItem(list l,char *data,BOOL inOrder)
917 *
918 * Use
919 * Adds a new piece of data into the list.
920 *
921 * Parameters
922 * list l == the list handle
923 * char *data == the data (as a char *, because most of the time you'll
924 * want to be using character strings).
925 *
926 * Returns
927 * A handle for the list item. This is 0 if the call failed.
928 */
929
930 list_item list_addItem(list l,char *data,BOOL inOrder)
931 {
932 list_item itm=(list_item)&(l->list);
933 list_item new=(list_item)mem_alloc(sizeof(list__item));
934 int len;
935
936 if (!new)
937 {
938 werr(FALSE,msgs_lookup("listNEMI:Not enough room to add new item."));
939 return (0);
940 }
941 if (new->data=mem_alloc(strlen(data)+1),!new->data)
942 {
943 mem_free(new);
944 werr(FALSE,msgs_lookup("listNEMI:Not enough room to add new item."));
945 return (0);
946 }
947 strcpy(new->data,data);
948 while (itm->next)
949 {
950 if (utils_caselessCmp(itm->next->data,data)>0 && inOrder==TRUE)
951 break;
952 itm=itm->next;
953 }
954 new->next=itm->next;
955 new->prev=itm;
956 itm->next=new;
957 if (new->next)
958 new->next->prev=new;
959 new->handle=0;
960 new->selected=FALSE;
961 new->nsel=FALSE;
962 l->items++;
963 len=wimpt_stringWidth(data);
964 if (len>l->width)
965 l->width=len;
966 list__resize(l);
967 return (new);
968 }
969
970 /*
971 * list_item list_findItem(list l,char *data)
972 *
973 * Use
974 * Searches through a list and returns the item number of the item whose
975 * data matches that given in the function.
976 *
977 * Parameters
978 * list l == the list handle
979 * char *data == the data to compare with
980 *
981 * Returns
982 * The item number of the item, or -1 if no match.
983 */
984
985 list_item list_findItem(list l,char *data)
986 {
987 list_item itm=l->list;
988 list_item found=list_NOITEM;
989 while (itm!=0)
990 {
991 if (utils_caselessCmp(itm->data,data)==0)
992 found=itm;
993 itm=itm->next;
994 }
995 return (found);
996 }
997
998 /*
999 * void list_removeItem(list l,list_item i)
1000 *
1001 * Use
1002 * Removes an item from the list.
1003 *
1004 * Parameters
1005 * list l == the list's handle
1006 * list_item i == the item number
1007 */
1008
1009 void list_removeItem(list l,list_item i)
1010 {
1011 if (i==l->selected)
1012 l->selected=list_NOITEM;
1013 if (i->selected)
1014 l->nsel--;
1015 if (i->prev)
1016 i->prev->next=i->next;
1017 if (i->next)
1018 i->next->prev=i->prev;
1019 l->items--;
1020 mem_free(i->data);
1021 mem_free(i);
1022 list__rescanSize(l);
1023 }
1024
1025 /*
1026 * void list_delete(list l)
1027 *
1028 * Use
1029 * Destroys a list totally.
1030 *
1031 * Parameters
1032 * list l == the list handle
1033 */
1034
1035 void list_delete(list l)
1036 {
1037 list_item itm=l->list;
1038 list_item i;
1039 if (l->wind)
1040 list_unlink(l);
1041 win_activedec();
1042 while (itm)
1043 {
1044 i=itm;
1045 itm=i->next;
1046 mem_free(i->data);
1047 mem_free(i);
1048 }
1049 mem_free(l);
1050 }
1051
1052 /*
1053 * void list_updatePosition(list l)
1054 *
1055 * Use
1056 * Writes the position of the listbox back into the template, so any new
1057 * list boxes created from the template open at that position.
1058 *
1059 * Parameters
1060 * list l == the list handle
1061 */
1062
1063 void list_updatePosition(list l)
1064 {
1065 wimp_winfo *w;
1066 if (w=(wimp_winfo *)mem_alloc
1067 (
1068 sizeof(wimp_winfo)+l->windDef->nicons*sizeof(wimp_icon)
1069 ),
1070 w);
1071 {
1072 w->w=l->wind;
1073 wimpt_noerr(wimp_get_wind_info(w));
1074 *(l->windDef)=w->info;
1075 l->windDef->colours[wimp_WCWKAREABACK]=l->backg;
1076 /* Put colour back into *your* life :-) */
1077 mem_free(w);
1078 }
1079 }
1080
1081 /*
1082 * BOOL list_link(list l)
1083 *
1084 * Use
1085 * Links a list box to a WIMP window. If the list is already linked,
1086 * nothing happens. The list box is not displayed.
1087 *
1088 * Parameters
1089 * list l == the list handle
1090 *
1091 * Returns
1092 * TRUE if the link succeeded (may run out of windows!)
1093 */
1094
1095 BOOL list_link(list l)
1096 {
1097 int ox,oy;
1098 if (l->wind!=0)
1099 return(TRUE);
1100 l->windDef->colours[wimp_WCWKAREABACK]=255;
1101 /* We draw the whole lot anyway, so this is quicker */
1102 if (wimp_create_wind(l->windDef,&l->wind))
1103 {
1104 werr
1105 (
1106 FALSE,
1107 msgs_lookup("listTMW:Too many windows - "
1108 "%s could not create list box."),
1109 wimpt_programname()
1110 );
1111 l->wind=0;
1112 l->windDef->colours[wimp_WCWKAREABACK]=l->backg;
1113 /* Put it back for reading again later */
1114 return (FALSE);
1115 }
1116 l->windDef->colours[wimp_WCWKAREABACK]=l->backg;
1117 /* Put it back for reading again later */
1118 win_register_event_handler(l->wind,_dllEntry(list__events),l);
1119 win_add_unknown_event_processor(list__modeChange,l);
1120 ox=l->windDef->box.x0-l->windDef->scx;
1121 oy=l->windDef->box.y1-l->windDef->scy;
1122 l->visSize.x0=l->windDef->ex.x0;
1123 l->visSize.y0=l->windDef->box.y0-oy;
1124 l->visSize.x1=l->windDef->ex.x1;
1125 l->visSize.y1=l->windDef->box.y1-oy;
1126 l->update=TRUE;
1127 list__rescanSize(l);
1128 return (TRUE);
1129 }
1130
1131 /*
1132 * void list_unlink(list l)
1133 *
1134 * Use
1135 * Unlinks the list box from its window and deletes the window.
1136 *
1137 * Parameters
1138 * list l == the list handle
1139 */
1140
1141 void list_unlink(list l)
1142 {
1143 if (l->wind==0)
1144 return;
1145 list_updatePosition(l);
1146 win_register_event_handler(l->wind,0,0);
1147 win_remove_unknown_event_processor(list__modeChange,l);
1148 wimpt_noerr(wimp_delete_wind(l->wind));
1149 l->wind=0;
1150 }
1151 /*
1152 * void list_unlinkNoUpdate(list l)
1153 *
1154 * Use
1155 * Unlinks a list from its window without storing its final position back
1156 * in memory. Note that list_delete() calls list_unlink(), so make sure
1157 * you call this routine before deleting the list box it you want to
1158 * prevent the position being written back.
1159 *
1160 * Parameters
1161 * list l == the list handle
1162 */
1163
1164 void list_unlinkNoUpdate(list l)
1165 {
1166 if (l->wind==0)
1167 return;
1168 win_register_event_handler(l->wind,0,0);
1169 wimpt_noerr(wimp_delete_wind(l->wind));
1170 l->wind=0;
1171 }
1172
1173
1174 /*
1175 * void list_update(list l,BOOL really)
1176 *
1177 * Use
1178 * Enables or disables list updating (i.e. whether the listbox resizes and
1179 * redraws itself between every operation). If you're going to do some
1180 * lengthy operation, it would be a good idea to turn update off first,
1181 * and then turn it on again afterwards.
1182 *
1183 * Note that this is an all-or-nothing thing -- no counter is kept.
1184 *
1185 * Parameters
1186 * list l == the listbox which we're messing about with
1187 * BOOL really == whether to turn the update on or off
1188 */
1189
1190 void list_update(list l,BOOL really)
1191 {
1192 l->update=really;
1193 if (really)
1194 list__rescanSize(l);
1195 }
1196
1197 /*
1198 * void list_display(list l)
1199 *
1200 * Use
1201 * Displays a list box on-screen
1202 *
1203 * Parameters
1204 * list l == the list
1205 */
1206
1207 void list_display(list l)
1208 {
1209 wimp_wstate state;
1210 if (l->wind==0)
1211 {
1212 if (list_link(l)==0)
1213 return;
1214 }
1215 wimpt_noerr(wimp_get_wind_state(l->wind,&state));
1216 state.o.behind=(wimp_w)-1;
1217 wimpt_noerr(wimp_open_wind(&state.o));
1218 }
1219
1220 /*
1221 * void list_openDisplaced(list l)
1222 *
1223 * Use
1224 * Opens the listbox on-screen displaced from its previous position by the
1225 * normal 48 OS units. It must be unlinked using list_unlinkNoUpdate
1226 * before deletion.
1227 *
1228 * Parameters
1229 * list l == the list handle.
1230 */
1231
1232 void list_openDisplaced(list l)
1233 {
1234 int new=0;
1235 wimp_wstate s;
1236 if (l->windDef->box.y0-48<132)
1237 {
1238 new=((976-l->windDef->box.y1)/48-4)*48+l->windDef->box.y1;
1239 l->windDef->box.y0+=new-l->windDef->box.y1;
1240 l->windDef->box.y1=new;
1241 }
1242 else
1243 {
1244 l->windDef->box.y0-=48;
1245 l->windDef->box.y1-=48;
1246 }
1247 wimpt_noerr(wimp_get_wind_state(l->wind,&s));
1248 s.o.box=l->windDef->box;
1249 s.o.behind=-1;
1250 wimpt_noerr(wimp_open_wind(&s.o));
1251 }
1252
1253 /*
1254 * void list_hide(list l)
1255 *
1256 * Use
1257 * Stops the list box being displayed
1258 *
1259 * Parameters
1260 * list l == the list handle
1261 */
1262
1263 void list_hide(list l)
1264 {
1265 wimpt_noerr(wimp_close_wind(l->wind));
1266 }
1267
1268 /*
1269 * wimp_w list_syshandle(list l)
1270 *
1271 * Use
1272 * Returns the WIMP window handle being used for the list box.
1273 *
1274 * Parameters
1275 * list l == the list
1276 *
1277 * Returns
1278 * The window handle (a wimp_w).
1279 */
1280
1281 wimp_w list_syshandle(list l)
1282 {
1283 return (l->wind);
1284 }
1285
1286 /*
1287 * void list_eventHandler(list l,list_eventhandler proc,void *handle)
1288 *
1289 * Use
1290 * Attaches an event handler to the list box. Most won't actually need
1291 * this, just the stand-alone ones, or ones that do clever-dick things.
1292 *
1293 * Parameters
1294 * list l == the list handle
1295 * list_eventhandler proc == the procedure to handle events
1296 * void *handle == the jolly olde pointer to the user-defined data
1297 */
1298
1299 void list_eventHandler(list l,list_eventhandler proc,void *handle)
1300 {
1301 l->events=proc;
1302 l->evntHandle=handle;
1303 }
1304
1305 /*
1306 * void list_rawEventHandler(list l,list_raweventhandler proc,void *handle)
1307 *
1308 * Use
1309 * Attaches the raw event handler procedure to the list box. You can then
1310 * vet any events coming into the list box and have your wicked way with
1311 * them.
1312 *
1313 * Parameters
1314 * list l == the list handle
1315 * list_raweventhandler proc == the raw event handler routine
1316 * void *handle == the (now-famous) caller defined handle.
1317 */
1318
1319 void list_rawEventHandler(list l,list_raweventhandler proc,void *handle)
1320 {
1321 l->rawEvents=proc;
1322 l->rawHandle=handle;
1323 }
1324
1325 /*
1326 * void list_redrawHandler(list l,list_redrawhandler rdr,void *handle)
1327 *
1328 * Use
1329 * Attaches a replacement redraw handler to the list box. The new handler
1330 * redraws individual items in the list. It must fill in the box it is
1331 * passed, because the WIMP does not fill in the background. The part of
1332 * the list box not populated by items is filled in the window background
1333 * colour automatically. Using this, you can achieve quite a pleasing
1334 * effect by making the background grey (colour 1) and the actual item
1335 * backgrounds white (colour 0), indicating clearly the bottom of the list.
1336 *
1337 * You can also implement other things like items being shaded etc.
1338 *
1339 * Parameters
1340 * list l == the list to which the redraw handler is to be attached
1341 * list_redrawhandler == the replacement redraw routine (or 0 to cancel)
1342 * void *handle == a pointer to pass the redraw routine
1343 */
1344
1345 void list_redrawHandler(list l,list_redrawhandler rdr,void *handle)
1346 {
1347 l->rdr=rdr;
1348 l->redrawHandle=handle;
1349 }
1350
1351 /*
1352 * void list_widthAdd(list l,int extra)
1353 *
1354 * Use
1355 * Since redraw handlers can basically do whatever they want to for each
1356 * items, the list manager no longer really has any idea about how wide an
1357 * item is. Since the main thing displayed in lists is text, it is assumed
1358 * that the width of an item is the width of the longest piece of text plus
1359 * a constant (e.g. for a sprite on the side). If this is not so, I'll
1360 * have to rethink this bit...
1361 *
1362 * Parameters
1363 * list l == the list we're setting the width of
1364 * int extra == the constant to add to each item
1365 */
1366
1367 void list_widthAdd(list l,int extra)
1368 {
1369 l->extraWidth=extra;
1370 list__resize(l); /* In case it's open */
1371 }
1372
1373 /*
1374 * void list_setItemHeight(list l,int height)
1375 *
1376 * Use
1377 * Sets the height of items in the specified list box. By default, the
1378 * height is 44 OS units (the height of menu items). This should be
1379 * sufficient for most purposes.
1380 *
1381 * Parameters
1382 * list l == the list to set
1383 * int height == the new height of each item, in OS units
1384 */
1385
1386 void list_setItemHeight(list l,int height)
1387 {
1388 l->iHeight=height;
1389 list__resize(l); /* In case it's open now */
1390 }
1391
1392 /*
1393 * int list_items(list l)
1394 *
1395 * Use
1396 * Informs the caller how many items there are in a list
1397 *
1398 * Parameters
1399 * list l == the list handle
1400 *
1401 * Returns
1402 * The number of items in a list
1403 */
1404
1405 int list_items(list l)
1406 {
1407 return (l->items);
1408 }
1409
1410 /*
1411 * void list_doForItems
1412 * (
1413 * list l,
1414 * void (*proc)(list l,list_item i,void *handle),
1415 * void *handle
1416 * )
1417 *
1418 * Use
1419 * Performs an operation on all of the items in a list box.
1420 *
1421 * Parameters
1422 * list l == the list handle
1423 * void (*proc)(list l,list_item i,void *handle) == the procedure to use
1424 * void *handle == a handle to pass to the procedure.
1425 */
1426
1427 void list_doForItems
1428 (
1429 list l,
1430 void (*proc)(list l,list_item i,void *handle),
1431 void *handle
1432 )
1433 {
1434 list_item i=l->list;
1435 list_item next;
1436 visdelay_begin();
1437 while (i)
1438 {
1439 next=i->next;
1440 proc(l,i,handle);
1441 i=next;
1442 }
1443 visdelay_end();
1444 }
1445
1446 /*
1447 * void list_attachData(list l,list_item i,void *data)
1448 *
1449 * Use
1450 * Attaches a data structure to a list item. This is a bit of an
1451 * afterthought really.
1452 *
1453 * Parameters
1454 * list l == the list
1455 * list_item i == the list item
1456 * void *data == a pointer to the data structure
1457 */
1458
1459 void list_attachData(list l,list_item i,void *data)
1460 {
1461 l=l;
1462 list__findItem(l,i)->handle=data;
1463 }
1464
1465 /*
1466 * void *list_getData(list l,list_item i)
1467 *
1468 * Use
1469 * Returns the data attached to a list item. The item number may have
1470 * changed etc. with items deleted and added.
1471 *
1472 * Parameters
1473 * list l == the list
1474 * list_item i == the list item number
1475 *
1476 * Returns
1477 * A pointer to the data structure attached using list_attachData().
1478 */
1479
1480 void *list_getData(list l,list_item i)
1481 {
1482 l=l;
1483 if (i!=list_NOITEM)
1484 return (list__findItem(l,i)->handle);
1485 else
1486 return (0);
1487 }
1488
1489 /*
1490 * void list_multipleSelection(list l)
1491 *
1492 * Use
1493 * Makes a list able to handle a multiple selection.
1494 *
1495 * Parameters
1496 * list l == the list handle
1497 */
1498
1499 void list_multipleSelection(list l)
1500 {
1501 l->multSel=TRUE;
1502 }
1503
1504 /*
1505 * BOOL list_addToSelection(list l,list_item i,list_action a)
1506 *
1507 * Use
1508 * Adds an item to the current selection.
1509 *
1510 * Parameters
1511 * list l == the list
1512 * list_item i == the list item
1513 * list_action a == what to do with the state
1514 *
1515 * Returns
1516 * The previous state of the item
1517 */
1518
1519 BOOL list_addToSelection(list l,list_item i,list_action a)
1520 {
1521 #ifdef notdef
1522 wimp_wstate state;
1523 int top;
1524 int bottom;
1525 int height;
1526 #endif
1527 BOOL ostate;
1528 if (i==list_NOITEM)
1529 return (FALSE);
1530 l->selected=i;
1531 ostate=i->selected;
1532 switch (a)
1533 {
1534 case list_SETSTATE:
1535 i->selected=TRUE;
1536 break;
1537 case list_RESETSTATE:
1538 i->selected=FALSE;
1539 break;
1540 case list_TOGGLESTATE:
1541 i->selected=!(i->selected);
1542 break;
1543 }
1544 l->nsel+=i->selected-ostate;
1545 if (l->wind==0 || i->selected==ostate)
1546 return (ostate);
1547 list__redrawItem(l,list_itemToIndex(l,l->selected));
1548 #ifdef notdef
1549 top=-l->iHeight*list_itemToIndex(l,i);
1550 bottom=top-l->iHeight;
1551 wimpt_noerr(wimp_get_wind_state(l->wind,&state));
1552 height=state.o.box.y1-state.o.box.y0;
1553 if (state.o.y<top)
1554 state.o.y=top;
1555 if (state.o.y-height>bottom)
1556 state.o.y=bottom+height;
1557 wimpt_noerr(wimp_open_wind(&state.o));
1558 #endif
1559 return (ostate);
1560 }
1561
1562 /*
1563 * void list_doForSelected
1564 * (
1565 * list l,
1566 * void (*proc)(list l,list_item i,void *handle),
1567 * void *handle
1568 * )
1569 *
1570 * Use
1571 * Performs a user-specified action for each selected list item.
1572 *
1573 * Parameters
1574 * list l == the list box
1575 * void (*proc)(list l,list_item i,void *handle) == the procedure to do
1576 * the thing
1577 * void *handle == a handle to pass to the routine.
1578 */
1579
1580 void list_doForSelected
1581 (
1582 list l,
1583 void (*proc)(list l,list_item i,void *handle),
1584 void *handle
1585 )
1586 {
1587 list_item i=l->list;
1588 list_item next;
1589 visdelay_begin();
1590 while (i)
1591 {
1592 next=i->next;
1593 if (i->selected)
1594 proc(l,i,handle);
1595 i=next;
1596 }
1597 visdelay_end();
1598 }
1599
1600 /*
1601 * void list__sel(list l,list_item i,void *handle)
1602 *
1603 * Use
1604 * Selects a single item in a list. This is a list_doForItems() procedure.
1605 *
1606 * Parameters
1607 * list l == the list
1608 * list_item i == the list item to select
1609 * void *handle == a pointer to a variable of type list_action
1610 */
1611
1612 static void list__sel(list l,list_item i,void *handle)
1613 {
1614 list_action *a=(list_action *)handle;
1615 list_addToSelection(l,i,*a);
1616 }
1617
1618 /*
1619 * void list_selectAll(list l,list_action a)
1620 *
1621 * Use
1622 * Selects all the items in a list
1623 *
1624 * Parameters
1625 * list l == the list
1626 * list_action a == what to do with the icons (list_READSTATE ain't all
1627 * that useful, and list_TOGGLESTATE is downright wierd).
1628 */
1629
1630 void list_selectAll(list l,list_action a)
1631 {
1632 list_doForItems(l,list__sel,&a);
1633 }
1634
1635 /*
1636 * int list_numSelected(list l)
1637 *
1638 * Use
1639 * Informs the caller how many items are selected.
1640 *
1641 * Parameters
1642 * list l == the list handle
1643 *
1644 * Returns
1645 * An integer indicating the number of selected items
1646 */
1647
1648 int list_numSelected(list l)
1649 {
1650 return (l->nsel);
1651 }
1652
1653 /*
1654 * int list_itemToIndex(list l,list_item i)
1655 *
1656 * Use
1657 * Translates a list_item into the index of the item. This avoids
1658 * assumptions about the mapping of indices to item numbers. In the
1659 * future, for example, the list_item data type may be used as a pointer to
1660 * the list item data structure in memory. Most of the time this will be
1661 * irrelevant anyway.
1662 *
1663 * Parameters
1664 * list l == the list handle
1665 * list_item i == the list item to translate
1666 *
1667 * Returns
1668 * An integer giving the index of the item. The first item has index 0, as
1669 * for C arrays.
1670 */
1671
1672 int list_itemToIndex(list l,list_item i)
1673 {
1674 int ind=0;
1675 list_item itm=l->list;
1676 while (itm)
1677 {
1678 if (itm==i)
1679 return (ind);
1680 itm=itm->next;
1681 ind++;
1682 }
1683 return (-1);
1684 }
1685
1686 /*
1687 * list_item list_indexToItem(list l,int index)
1688 *
1689 * Use
1690 * Performs the reverse operation to the previous routine. It will
1691 * translate an index to a list_item.
1692 *
1693 * Parameters
1694 * list l == the list handle
1695 * int index == the index of the item required
1696 *
1697 * Returns
1698 * The equivalent list_item for the item.
1699 */
1700
1701 list_item list_indexToItem(list l,int index)
1702 {
1703 int ind=0;
1704 list_item itm=l->list;
1705 while (itm)
1706 {
1707 if (ind==index)
1708 return (itm);
1709 itm=itm->next;
1710 ind++;
1711 }
1712 return (list_NOITEM);
1713 }
1714
1715 /*
1716 * list_item list_helpItem(list l)
1717 *
1718 * Use
1719 * Returns the item that Help is interested in.
1720 *
1721 * Parameters
1722 * list l == the list's handle
1723 *
1724 * Returns
1725 * A list_item
1726 */
1727
1728 list_item list_helpItem(list l)
1729 {
1730 wimp_eventstr *e=wimpt_last_event();
1731 if (help_wasHelp())
1732 return (list__coordsToItem
1733 (
1734 e->data.msg.data.helprequest.m.x,
1735 e->data.msg.data.helprequest.m.y,l
1736 ));
1737 else
1738 werr(TRUE,msgs_lookup("listHIE:(list_helpItem, caller fault): "
1739 "Not called on HELPREQUEST event."));
1740 return (0);
1741 }