/* * ListBox * Provides handling for list boxes * * v. 1.00 (27 July 1993) * * © 1993-1998 Straylight */ /*----- Licensing note ----------------------------------------------------* * * This file is part of Straylight's Steel library. * * Steel is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * Steel is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Steel. If not, write to the Free Software Foundation, * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "wimp.h" #include "wimpt.h" #include "event.h" #include "win.h" #include "template.h" #include "listbox.h" #include "werr.h" #include "msgs.h" #include "bbc.h" #include "mem.h" #include "utils.h" #include "help.h" #include "visdelay.h" #include "dll.h" #ifndef _dll_NODLL extern void _dllEntry(list__events)(wimp_eventstr *e,void *handle); #endif #define list__ITEMHEIGHT 44 #define list__MINHEIGHT 176 /* * A structure for the list items */ typedef struct list__item { struct list__item *next; struct list__item *prev; void *handle; char *data; BOOL selected :1; BOOL nsel :1; } list__item; /* * A structure that says everything about a listbox */ typedef struct list__liststr { wimp_w wind; wimp_box visSize; wimp_wind *windDef; int foreg; int backg; list_eventhandler events; void *evntHandle; list_raweventhandler rawEvents; void *rawHandle; list_redrawhandler rdr; void *redrawHandle; int items; int width; list_item selected; list_item list; int nsel; pane p; int iHeight; int extWidth; int extraWidth; BOOL alterSize :1; BOOL multSel :1; BOOL update :1; } list__liststr; static list list__dragging; static int list__dragIndex; static int list__currentIndex; _dll_static void list__events(wimp_eventstr *e,void *handle); /* * void list__resize(list l) * * Use * This routine will resize a list box according to how many items there * are in it. * * Parameters * list l == the list handle */ static void list__resize(list l) { wimp_wstate s; int height; int width; BOOL open; int maxlen; wimp_redrawstr extent; wimp_box b; BOOL hscr=FALSE,ohscr; BOOL vscr=FALSE,ovscr; wimp_winfo w; menu_handler mhnd; pane p=0; int xe=0,ye=0; int scbh=0; /* --- Find out if there's anything to do --- */ if (!l->wind || !l->update) return; /* --- Get information about the window --- */ wimpt_noerr(wimp_get_wind_state(l->wind,&s)); open=s.flags & wimp_WOPEN; height=l->items*l->iHeight; width=maxlen=l->width+16+l->extraWidth; /* --- If it's a pane listbox, add in scroll bars if necessary --- */ if (!l->alterSize) { /* --- First, read the position and scroll sizes --- */ win_gadgetWidths(wimp_WNEW | wimp_WVSCR | wimp_WHSCR,&b); /* --- Get the outline extents of the window --- */ ohscr=s.flags & wimp_WHSCR; ovscr=s.flags & wimp_WVSCR; scbh=b.y0-wimpt_dy(); xe=s.o.box.x1-s.o.box.x0+(ovscr ? b.x1-wimpt_dx() : 0); ye=s.o.box.y1-s.o.box.y0+(ohscr ? scbh : 0); /* --- Now find out if we really want scroll bars --- */ if (maxlen>xe) { hscr=TRUE; ye-=b.y0-wimpt_dy(); } if (height>ye) { vscr=TRUE; xe-=b.x1-wimpt_dx(); } if (!hscr && maxlen>xe) { hscr=TRUE; ye-=b.y0-wimpt_dy(); } /* --- If we changed the scroll bars, recreate the window --- */ if (!hscr!=!ohscr || !vscr!=!ovscr) { /* --- Update the scroll bar flags --- */ ohscr=hscr; ovscr=vscr; /* --- Save all the window's info so we recreate it properly --- */ if (l->p) { p=l->p; pane_removePane(p,l->wind); } w.w=l->wind; wimpt_noerr(wimp_get_wind_info(&w)); menu_saveHandler(l->wind,&mhnd); wimpt_noerr(wimp_delete_wind(l->wind)); win_register_event_handler(l->wind,0,0); /* --- Set up window with new scroll bar gadgetry --- */ w.info.flags&=~(wimp_WHSCR | wimp_WVSCR); if (hscr) w.info.flags|=wimp_WHSCR; if (vscr) w.info.flags|=wimp_WVSCR; w.info.flags|=wimp_WNEW; w.info.ex.x1+=200; w.info.ex.y0-=200; wimpt_noerr(wimp_create_wind(&w.info,&l->wind)); /* --- Read the new outline and check the sizes again --- */ s.o.w=l->wind; s.o.box.x1=s.o.box.x0+xe; s.o.box.y0=s.o.box.y1-ye; wimpt_noerr(wimp_open_wind(&s.o)); /* --- Restore everything we saved above --- */ if (!open) wimpt_noerr(wimp_close_wind(l->wind)); win_register_event_handler(l->wind,_dllEntry(list__events),l); menu_restoreHandler(l->wind,&mhnd); } } else xe=l->visSize.x1-l->visSize.x0; /* --- Correct the extent dimensions --- */ if (widthalterSize) height=ye; if (heightwind; extent.box.x0=l->visSize.x0; extent.box.x1=l->visSize.x0+width; extent.box.y0=-height; extent.box.y1=0; l->extWidth=width; /* Remember the width of the window for redrawing */ wimpt_noerr(wimp_set_extent(&extent)); if (open) { wimpt_noerr(wimp_open_wind(&s.o)); wimpt_noerr(wimp_force_redraw(&extent)); } if (p) { l->p=p; pane_addListbox(p,l); } } /* * void list__rescanSize(list l) * * Use * Recalculates a list box's width. */ static void list__rescanSize(list l) { list_item itm; int len; if (!l->wind || !l->update) return; l->width=0; itm=l->list; while (itm) { len=wimpt_stringWidth(itm->data); if (len>l->width) l->width=len; itm=itm->next; } list__resize(l); } /* * void list__event(list l,list_item clicked) * * Use * Posts an event to the event handler registered for the list box (if it's * there). * * Parameters * list l == the list box handle * list_item clicked == the item that was clicked */ static void list__event(list l,list_item clicked) { if (l->events) (l->events)(l,clicked,l->evntHandle); } /* * void list__defaultRedraw(list l, * wimp_box *b, * char *text, * BOOL selected) * * Use * Standard redraw handler for list boxes. This may be overridden if the * list box is a fancy one. * * Parameters * As for list redraw handlers, except that there's no handle passed to it. */ static void list__defaultRedraw(list l, wimp_box *b, char *text, BOOL selected) { wimp_icon icn; icn.box=*b; icn.flags=0x00000131+(l->foreg<<24)+(l->backg<<28); icn.data.indirecttext.validstring=(char *)-1; icn.data.indirecttext.bufflen=0; if (selected) icn.flags|=wimp_ISELECTED; else icn.flags&=~wimp_ISELECTED; icn.data.indirecttext.buffer=text; wimpt_noerr(wimp_ploticon(&icn)); } /* * void list__redraw(wimp_redrawstr *r,void *handle) * * Use * Redraws a list box window * * Parameters * wimp_redrawstr *r == redraw structure for this redraw event * void *handle == pointer to this list box */ static void list__redraw(wimp_redrawstr *r,void *handle) { list l=(list)handle; list_item itm=l->list; int ox=r->box.x0-r->scx; int oy=r->box.y1-r->scy; int i=0; int first=-(r->g.y1-r->box.y1+r->scy)/l->iHeight; int last=first+(r->g.y1-r->g.y0)/l->iHeight+1; wimp_box box; box.x0=l->visSize.x0; box.x1=l->visSize.x0+l->extWidth; box.y1=0; box.y0=-l->iHeight; while (itm) { if (i>=first && i<=last) { if (l->rdr) { (l->rdr)(l,itm,r,&box,itm->data, itm->selected || itm->nsel,l->redrawHandle); } else list__defaultRedraw(l,&box,itm->data,itm->selected || itm->nsel); } itm=itm->next; box.y0-=l->iHeight; box.y1-=l->iHeight; i++; } wimpt_noerr(wimp_setcolour(l->backg)); if (i<=last) { bbc_rectanglefill(l->visSize.x0+ox, box.y1+oy-l->iHeight*(last-i+1)-wimpt_dy(), l->extWidth, l->iHeight*(last-i+1)); } } /* * list_item list__coordsToItem(int x,int y,list l) * * Use * Given a screen position and a list handle, returns * the item beneath the point. * * Parameters * int x == absolute OS-unit screen x-coordinate of the point * int y == absolute OS-unit screen y-coordinate of the point * list l == the list handle * * Returns * The list item handle */ static list_item list__coordsToItem(int x,int y,list l) { wimp_wstate state; int oy; list_item i; int index; x=x; wimpt_noerr(wimp_get_wind_state(l->wind,&state)); oy=state.o.box.y1-state.o.y; index=-(y-oy+wimpt_dy())/l->iHeight; if (index>=l->items) return (list_NOITEM); i=list_indexToItem(l,index); return (i); } /* * void list__selectIdles(void *handle) * * Use * Gets passed idle events when dragging out a selection. * * Parameters * void *handle == a NULL pointer */ #define min2(x,y) ((x)<(y) ? (x) : (y)) #define max2(x,y) ((x)>(y) ? (x) : (y)) #define min3(x,y,z) min2(min2(x,y),z) #define max3(x,y,z) max2(max2(x,y),z) static void list__redrawItem(list l,int i); static void list__selectIdles(void *handle) { /* --- Rewritten 24-Jun-1993 - MDW --- */ /* --- Variables required to update the drag --- */ wimp_mousestr m; /* Pointer state (window coords) */ wimp_wstate s; /* Position of window */ int ox,oy; /* Screen coords of window origin */ int i; /* Item index counter */ int start; /* Index to start processing items */ int end; /* Index to finish processing items */ int index; /* Index of item under pointer */ list_item item; /* List item ptr (for list traverse) */ int sel; /* -1 == ignore, 0 == deselect, */ /* 1 == select */ handle=handle; /* --- Set up pointer position --- */ wimpt_noerr(wimp_get_point_info(&m)); /* I only need the coordinates */ wimpt_noerr(wimp_get_wind_state(list__dragging->wind,&s)); /* For origin,*/ /* and scrolling the window */ ox=s.o.box.x0-s.o.x; /* Derive position of window origin */ oy=s.o.box.y1-s.o.y; /* from state as per PRM */ m.x-=ox; /* Now convert mouse position to */ m.y-=oy; /* window coordinates */ index=-(m.y+wimpt_dy())/list__dragging->iHeight; /* Calc item under ptr */ if (index<0) /* Stop negative indices */ index=0; /* --- Set up for loop through list items --- */ start=min3(list__currentIndex,list__dragIndex,index); end=max3(list__currentIndex,list__dragIndex,index); item=list__dragging->list; i=0; sel=-1; /* --- Now loop through the relevant icons --- */ while (item) /* Carry on until we run out of items*/ { if (i==start) sel=0; if (list__dragIndexselected && sel!=item->nsel) { item->nsel=sel; list__redrawItem(list__dragging,i); list__dragging->nsel+=(sel==TRUE)-(sel==FALSE); } i++; item=item->next; } list__currentIndex=index; /* --- Scroll the window to include the added selection --- */ if (m.y>s.o.y) /* If pointer too far up, scroll up */ s.o.y=m.y; else if (m.y+s.o.box.y1-s.o.box.y0e) { case wimp_EUSERDRAG: list__selectIdles(0); for (i=list__dragging->list;i;i=i->next) { if (i->nsel) i->selected=TRUE; i->nsel=FALSE; } win_remove_unknown_event_processor(list__selectUnknowns,0); win_remove_idle_claimer(list__selectIdles,0); handled=TRUE; break; } return (handled); } /* * BOOL list__modeChange(wimp_eventstr *e,void *handle) * * Use * Handles mode change events for list boxes (rescan the width) */ static BOOL list__modeChange(wimp_eventstr *e,void *handle) { list l=handle; switch (e->e) { case wimp_ESEND: case wimp_ESENDWANTACK: if (e->data.msg.hdr.action==wimp_MMODECHANGE || e->data.msg.hdr.action==0x400CF) list__rescanSize(l); break; } return (FALSE); } /* * void list__events(wimp_eventstr *e,void *handle) * * Use * The event handler for list boxes. * * Parameters * wimp_eventstr *e == the event * void *handle == the list box handle */ _dll_static void list__events(wimp_eventstr *e,void *handle) { list l=(list)handle; BOOL handled=FALSE; if (l->rawEvents) handled=(l->rawEvents)(l,e,l->rawHandle); if (!handled) { switch (e->e) { case wimp_EREDRAW: wimpt_redraw(list__redraw,l); break; case wimp_EOPEN: wimpt_noerr(wimp_open_wind(&e->data.o)); break; case wimp_ECLOSE: list__event(l,list_CLOSE); break; case wimp_EBUT: if ( e->data.but.m.bbits & wimp_BLEFT || e->data.but.m.bbits & wimp_BRIGHT || e->data.but.m.bbits & wimp_BCLICKLEFT || e->data.but.m.bbits & wimp_BCLICKRIGHT ) { list_item i=list__coordsToItem(e->data.but.m.x,e->data.but.m.y,l); if (e->data.but.m.bbits&wimp_BLEFT || l->multSel==FALSE) list_selectItem(l,i); else list_addToSelection(l,i,list_TOGGLESTATE); list__event(l,l->selected); } else if ( (e->data.but.m.bbits & wimp_BDRAGLEFT || e->data.but.m.bbits & wimp_BDRAGRIGHT) && l->multSel==TRUE ) { wimp_dragstr d; wimp_wstate s; wimpt_noerr(wimp_get_wind_state(l->wind,&s)); d.type=wimp_USER_HIDDEN; d.parent.x0=e->data.but.m.x; d.parent.y0=0x9001; d.parent.x1=e->data.but.m.x; d.parent.y1=0x6FFE; wimpt_noerr(wimp_drag_box(&d)); list__dragging=l; list__dragIndex=-(e->data.but.m.y+wimpt_dy()-s.o.box.y1+s.o.y)/ l->iHeight; list__currentIndex=list__dragIndex; list__selectIdles(0); win_add_unknown_event_processor(list__selectUnknowns,0); win_addIdleClaimer(list__selectIdles,2,0); } break; case wimp_EKEY: wimpt_noerr(wimp_processkey(e->data.key.chcode)); break; case wimp_ESCROLL: { int height=e->data.scroll.o.box.y1-e->data.scroll.o.box.y0; int width=e->data.scroll.o.box.x1-e->data.scroll.o.box.x0; switch (e->data.scroll.y) { case -2: { int bottom=-(e->data.scroll.o.y-height)/l->iHeight; int itms=height/l->iHeight; if (-bottom*l->iHeight==e->data.scroll.o.y-height) bottom--; e->data.scroll.o.y=-(bottom+itms)*l->iHeight+height; } break; case -1: { int bottom=-(e->data.scroll.o.y-height)/l->iHeight; bottom++; e->data.scroll.o.y=-bottom*l->iHeight+height; } break; case 0: break; case 1: { int top=-(e->data.scroll.o.y)/l->iHeight; if (-top*l->iHeight==e->data.scroll.o.y) top--; e->data.scroll.o.y=-top*l->iHeight; } break; case 2: { int top=-(e->data.scroll.o.y)/l->iHeight; int itms=height/l->iHeight; if (-top*l->iHeight!=e->data.scroll.o.y); top++; e->data.scroll.o.y=-(top-itms)*l->iHeight; } break; } switch (e->data.scroll.x) { case -2: e->data.scroll.o.x-=width; break; case -1: e->data.scroll.o.x-=32; break; case 0: break; case 1: e->data.scroll.o.x+=32; break; case 2: e->data.scroll.o.x+=width; break; } wimpt_noerr(wimp_open_wind(&(e->data.scroll.o))); } break; case wimp_ESEND: case wimp_ESENDWANTACK: switch (e->data.msg.hdr.action) { case wimp_MHELPREQUEST: list__event(l,list_HELP); break; } break; } } } /* * list_item list__findItem(list l,list_item i) * * Use * Returns a pointer to a list item. * * Parameters * list l == the list * list_item i == the item number * * Returns * A pointer to the list item or 0 if it couldn't be found. */ #define list__findItem(l,i) (i) /* * void list_isPane(list l,pane p) * * Use * This routine is part of the private interface between the listbox and * pane segments. Do *NOT* try to call it in your own code. */ void list_isPane(list l,pane p) { l->p=p; if (l->p!=p && p) list__resize(l); } /* * void list__redrawItem(list l,int item) * * Use * Calls for a redraw of a single list item * * Parameters * list l == the list handle * int i == the item index */ static void list__redrawItem(list l,int i) { wimp_redrawstr r; wimp_wstate s; BOOL more; if (i!=-1) { wimpt_noerr(wimp_get_wind_state(l->wind,&s)); r.w=l->wind; r.box.x0=s.o.x; r.box.x1=s.o.x+s.o.box.x1-s.o.box.x0; r.box.y0=-l->iHeight*i-l->iHeight; r.box.y1=-l->iHeight*i; wimpt_noerr(wimp_update_wind(&r,&more)); while (more) { list__redraw(&r,l); wimpt_noerr(wimp_get_rectangle(&r,&more)); } } } /* * void list_selectItem(list l,list_item item) * * Use * Makes the item the currently selected one. * * Parameters * list l == the list handle * list_item item == the item number */ void list_selectItem(list l,list_item item) { list_item i=l->list; int c=0; visdelay_begin(); while (i) { if (i->selected==TRUE && i!=item) { i->selected=FALSE; list__redrawItem(l,c); l->nsel--; } c++; i=i->next; } visdelay_end(); l->selected=list_NOITEM; list_addToSelection(l,item,list_SETSTATE); } /* * list_item list_selected(list l) * * Use * Returns the currently selected item of the list. * * Parameters * list l == the list handle * * Returns * The item number of the currently selected item. */ list_item list_selected(list l) { list_item itm=l->list; while (itm) { if (itm->selected) return (itm); itm=itm->next; } return (list_NOITEM); } /* * list list_create(char *name,BOOL alterSize) * * Use * Creates a new list box window, and returns a handle to it. Initially, * there are no items, and the list box is not shown. The function returns * 0 if the call fails for one reason or another (not enough windows or * memory). * * Parameters * char *name == the name to match in the template file * BOOL alterSize == TRUE if we are allowed to change the box's visible * size. * * Returns * An abstract handle for the list box. */ list list_create(char *name,BOOL alterSize) { list new=(list)mem_alloc(sizeof(list__liststr)); if (new==0) { werr(FALSE,msgs_lookup("listNEM:Not enough room to create list box.")); return (0); } win_activeinc(); new->events=0; new->rawEvents=0; new->items=0; new->width=0; new->list=0; new->selected=list_NOITEM; new->windDef=template_syshandle(name); new->alterSize=alterSize; new->wind=0; new->foreg=new->windDef->colours[wimp_WCWKAREAFORE]; new->backg=new->windDef->colours[wimp_WCWKAREABACK]; new->multSel=FALSE; new->nsel=0; new->p=0; new->rdr=0; new->extraWidth=0; new->iHeight=list__ITEMHEIGHT; return (new); } /* * char *list_itemData(list l,list_item i) * * Use * Returns the string for an item * * Parameters * list l == the list handle * list_item i == the item's handle * * Returns * A pointer to the item's data */ char *list_itemData(list l,list_item i) { l=l; return (list__findItem(l,i)->data); } /* * list_item list_addItem(list l,char *data,BOOL inOrder) * * Use * Adds a new piece of data into the list. * * Parameters * list l == the list handle * char *data == the data (as a char *, because most of the time you'll * want to be using character strings). * * Returns * A handle for the list item. This is 0 if the call failed. */ list_item list_addItem(list l,char *data,BOOL inOrder) { list_item itm=(list_item)&(l->list); list_item new=(list_item)mem_alloc(sizeof(list__item)); int len; if (!new) { werr(FALSE,msgs_lookup("listNEMI:Not enough room to add new item.")); return (0); } if (new->data=mem_alloc(strlen(data)+1),!new->data) { mem_free(new); werr(FALSE,msgs_lookup("listNEMI:Not enough room to add new item.")); return (0); } strcpy(new->data,data); while (itm->next) { if (utils_caselessCmp(itm->next->data,data)>0 && inOrder==TRUE) break; itm=itm->next; } new->next=itm->next; new->prev=itm; itm->next=new; if (new->next) new->next->prev=new; new->handle=0; new->selected=FALSE; new->nsel=FALSE; l->items++; len=wimpt_stringWidth(data); if (len>l->width) l->width=len; list__resize(l); return (new); } /* * list_item list_findItem(list l,char *data) * * Use * Searches through a list and returns the item number of the item whose * data matches that given in the function. * * Parameters * list l == the list handle * char *data == the data to compare with * * Returns * The item number of the item, or -1 if no match. */ list_item list_findItem(list l,char *data) { list_item itm=l->list; list_item found=list_NOITEM; while (itm!=0) { if (utils_caselessCmp(itm->data,data)==0) found=itm; itm=itm->next; } return (found); } /* * void list_removeItem(list l,list_item i) * * Use * Removes an item from the list. * * Parameters * list l == the list's handle * list_item i == the item number */ void list_removeItem(list l,list_item i) { if (i==l->selected) l->selected=list_NOITEM; if (i->selected) l->nsel--; if (i->prev) i->prev->next=i->next; if (i->next) i->next->prev=i->prev; l->items--; mem_free(i->data); mem_free(i); list__rescanSize(l); } /* * void list_delete(list l) * * Use * Destroys a list totally. * * Parameters * list l == the list handle */ void list_delete(list l) { list_item itm=l->list; list_item i; if (l->wind) list_unlink(l); win_activedec(); while (itm) { i=itm; itm=i->next; mem_free(i->data); mem_free(i); } mem_free(l); } /* * void list_updatePosition(list l) * * Use * Writes the position of the listbox back into the template, so any new * list boxes created from the template open at that position. * * Parameters * list l == the list handle */ void list_updatePosition(list l) { wimp_winfo *w; if (w=(wimp_winfo *)mem_alloc ( sizeof(wimp_winfo)+l->windDef->nicons*sizeof(wimp_icon) ), w); { w->w=l->wind; wimpt_noerr(wimp_get_wind_info(w)); *(l->windDef)=w->info; l->windDef->colours[wimp_WCWKAREABACK]=l->backg; /* Put colour back into *your* life :-) */ mem_free(w); } } /* * BOOL list_link(list l) * * Use * Links a list box to a WIMP window. If the list is already linked, * nothing happens. The list box is not displayed. * * Parameters * list l == the list handle * * Returns * TRUE if the link succeeded (may run out of windows!) */ BOOL list_link(list l) { int ox,oy; if (l->wind!=0) return(TRUE); l->windDef->colours[wimp_WCWKAREABACK]=255; /* We draw the whole lot anyway, so this is quicker */ if (wimp_create_wind(l->windDef,&l->wind)) { werr ( FALSE, msgs_lookup("listTMW:Too many windows - " "%s could not create list box."), wimpt_programname() ); l->wind=0; l->windDef->colours[wimp_WCWKAREABACK]=l->backg; /* Put it back for reading again later */ return (FALSE); } l->windDef->colours[wimp_WCWKAREABACK]=l->backg; /* Put it back for reading again later */ win_register_event_handler(l->wind,_dllEntry(list__events),l); win_add_unknown_event_processor(list__modeChange,l); ox=l->windDef->box.x0-l->windDef->scx; oy=l->windDef->box.y1-l->windDef->scy; l->visSize.x0=l->windDef->ex.x0; l->visSize.y0=l->windDef->box.y0-oy; l->visSize.x1=l->windDef->ex.x1; l->visSize.y1=l->windDef->box.y1-oy; l->update=TRUE; list__rescanSize(l); return (TRUE); } /* * void list_unlink(list l) * * Use * Unlinks the list box from its window and deletes the window. * * Parameters * list l == the list handle */ void list_unlink(list l) { if (l->wind==0) return; list_updatePosition(l); win_register_event_handler(l->wind,0,0); win_remove_unknown_event_processor(list__modeChange,l); wimpt_noerr(wimp_delete_wind(l->wind)); l->wind=0; } /* * void list_unlinkNoUpdate(list l) * * Use * Unlinks a list from its window without storing its final position back * in memory. Note that list_delete() calls list_unlink(), so make sure * you call this routine before deleting the list box it you want to * prevent the position being written back. * * Parameters * list l == the list handle */ void list_unlinkNoUpdate(list l) { if (l->wind==0) return; win_register_event_handler(l->wind,0,0); wimpt_noerr(wimp_delete_wind(l->wind)); l->wind=0; } /* * void list_update(list l,BOOL really) * * Use * Enables or disables list updating (i.e. whether the listbox resizes and * redraws itself between every operation). If you're going to do some * lengthy operation, it would be a good idea to turn update off first, * and then turn it on again afterwards. * * Note that this is an all-or-nothing thing -- no counter is kept. * * Parameters * list l == the listbox which we're messing about with * BOOL really == whether to turn the update on or off */ void list_update(list l,BOOL really) { l->update=really; if (really) list__rescanSize(l); } /* * void list_display(list l) * * Use * Displays a list box on-screen * * Parameters * list l == the list */ void list_display(list l) { wimp_wstate state; if (l->wind==0) { if (list_link(l)==0) return; } wimpt_noerr(wimp_get_wind_state(l->wind,&state)); state.o.behind=(wimp_w)-1; wimpt_noerr(wimp_open_wind(&state.o)); } /* * void list_openDisplaced(list l) * * Use * Opens the listbox on-screen displaced from its previous position by the * normal 48 OS units. It must be unlinked using list_unlinkNoUpdate * before deletion. * * Parameters * list l == the list handle. */ void list_openDisplaced(list l) { int new=0; wimp_wstate s; if (l->windDef->box.y0-48<132) { new=((976-l->windDef->box.y1)/48-4)*48+l->windDef->box.y1; l->windDef->box.y0+=new-l->windDef->box.y1; l->windDef->box.y1=new; } else { l->windDef->box.y0-=48; l->windDef->box.y1-=48; } wimpt_noerr(wimp_get_wind_state(l->wind,&s)); s.o.box=l->windDef->box; s.o.behind=-1; wimpt_noerr(wimp_open_wind(&s.o)); } /* * void list_hide(list l) * * Use * Stops the list box being displayed * * Parameters * list l == the list handle */ void list_hide(list l) { wimpt_noerr(wimp_close_wind(l->wind)); } /* * wimp_w list_syshandle(list l) * * Use * Returns the WIMP window handle being used for the list box. * * Parameters * list l == the list * * Returns * The window handle (a wimp_w). */ wimp_w list_syshandle(list l) { return (l->wind); } /* * void list_eventHandler(list l,list_eventhandler proc,void *handle) * * Use * Attaches an event handler to the list box. Most won't actually need * this, just the stand-alone ones, or ones that do clever-dick things. * * Parameters * list l == the list handle * list_eventhandler proc == the procedure to handle events * void *handle == the jolly olde pointer to the user-defined data */ void list_eventHandler(list l,list_eventhandler proc,void *handle) { l->events=proc; l->evntHandle=handle; } /* * void list_rawEventHandler(list l,list_raweventhandler proc,void *handle) * * Use * Attaches the raw event handler procedure to the list box. You can then * vet any events coming into the list box and have your wicked way with * them. * * Parameters * list l == the list handle * list_raweventhandler proc == the raw event handler routine * void *handle == the (now-famous) caller defined handle. */ void list_rawEventHandler(list l,list_raweventhandler proc,void *handle) { l->rawEvents=proc; l->rawHandle=handle; } /* * void list_redrawHandler(list l,list_redrawhandler rdr,void *handle) * * Use * Attaches a replacement redraw handler to the list box. The new handler * redraws individual items in the list. It must fill in the box it is * passed, because the WIMP does not fill in the background. The part of * the list box not populated by items is filled in the window background * colour automatically. Using this, you can achieve quite a pleasing * effect by making the background grey (colour 1) and the actual item * backgrounds white (colour 0), indicating clearly the bottom of the list. * * You can also implement other things like items being shaded etc. * * Parameters * list l == the list to which the redraw handler is to be attached * list_redrawhandler == the replacement redraw routine (or 0 to cancel) * void *handle == a pointer to pass the redraw routine */ void list_redrawHandler(list l,list_redrawhandler rdr,void *handle) { l->rdr=rdr; l->redrawHandle=handle; } /* * void list_widthAdd(list l,int extra) * * Use * Since redraw handlers can basically do whatever they want to for each * items, the list manager no longer really has any idea about how wide an * item is. Since the main thing displayed in lists is text, it is assumed * that the width of an item is the width of the longest piece of text plus * a constant (e.g. for a sprite on the side). If this is not so, I'll * have to rethink this bit... * * Parameters * list l == the list we're setting the width of * int extra == the constant to add to each item */ void list_widthAdd(list l,int extra) { l->extraWidth=extra; list__resize(l); /* In case it's open */ } /* * void list_setItemHeight(list l,int height) * * Use * Sets the height of items in the specified list box. By default, the * height is 44 OS units (the height of menu items). This should be * sufficient for most purposes. * * Parameters * list l == the list to set * int height == the new height of each item, in OS units */ void list_setItemHeight(list l,int height) { l->iHeight=height; list__resize(l); /* In case it's open now */ } /* * int list_items(list l) * * Use * Informs the caller how many items there are in a list * * Parameters * list l == the list handle * * Returns * The number of items in a list */ int list_items(list l) { return (l->items); } /* * void list_doForItems * ( * list l, * void (*proc)(list l,list_item i,void *handle), * void *handle * ) * * Use * Performs an operation on all of the items in a list box. * * Parameters * list l == the list handle * void (*proc)(list l,list_item i,void *handle) == the procedure to use * void *handle == a handle to pass to the procedure. */ void list_doForItems ( list l, void (*proc)(list l,list_item i,void *handle), void *handle ) { list_item i=l->list; list_item next; visdelay_begin(); while (i) { next=i->next; proc(l,i,handle); i=next; } visdelay_end(); } /* * void list_attachData(list l,list_item i,void *data) * * Use * Attaches a data structure to a list item. This is a bit of an * afterthought really. * * Parameters * list l == the list * list_item i == the list item * void *data == a pointer to the data structure */ void list_attachData(list l,list_item i,void *data) { l=l; list__findItem(l,i)->handle=data; } /* * void *list_getData(list l,list_item i) * * Use * Returns the data attached to a list item. The item number may have * changed etc. with items deleted and added. * * Parameters * list l == the list * list_item i == the list item number * * Returns * A pointer to the data structure attached using list_attachData(). */ void *list_getData(list l,list_item i) { l=l; if (i!=list_NOITEM) return (list__findItem(l,i)->handle); else return (0); } /* * void list_multipleSelection(list l) * * Use * Makes a list able to handle a multiple selection. * * Parameters * list l == the list handle */ void list_multipleSelection(list l) { l->multSel=TRUE; } /* * BOOL list_addToSelection(list l,list_item i,list_action a) * * Use * Adds an item to the current selection. * * Parameters * list l == the list * list_item i == the list item * list_action a == what to do with the state * * Returns * The previous state of the item */ BOOL list_addToSelection(list l,list_item i,list_action a) { #ifdef notdef wimp_wstate state; int top; int bottom; int height; #endif BOOL ostate; if (i==list_NOITEM) return (FALSE); l->selected=i; ostate=i->selected; switch (a) { case list_SETSTATE: i->selected=TRUE; break; case list_RESETSTATE: i->selected=FALSE; break; case list_TOGGLESTATE: i->selected=!(i->selected); break; } l->nsel+=i->selected-ostate; if (l->wind==0 || i->selected==ostate) return (ostate); list__redrawItem(l,list_itemToIndex(l,l->selected)); #ifdef notdef top=-l->iHeight*list_itemToIndex(l,i); bottom=top-l->iHeight; wimpt_noerr(wimp_get_wind_state(l->wind,&state)); height=state.o.box.y1-state.o.box.y0; if (state.o.ybottom) state.o.y=bottom+height; wimpt_noerr(wimp_open_wind(&state.o)); #endif return (ostate); } /* * void list_doForSelected * ( * list l, * void (*proc)(list l,list_item i,void *handle), * void *handle * ) * * Use * Performs a user-specified action for each selected list item. * * Parameters * list l == the list box * void (*proc)(list l,list_item i,void *handle) == the procedure to do * the thing * void *handle == a handle to pass to the routine. */ void list_doForSelected ( list l, void (*proc)(list l,list_item i,void *handle), void *handle ) { list_item i=l->list; list_item next; visdelay_begin(); while (i) { next=i->next; if (i->selected) proc(l,i,handle); i=next; } visdelay_end(); } /* * void list__sel(list l,list_item i,void *handle) * * Use * Selects a single item in a list. This is a list_doForItems() procedure. * * Parameters * list l == the list * list_item i == the list item to select * void *handle == a pointer to a variable of type list_action */ static void list__sel(list l,list_item i,void *handle) { list_action *a=(list_action *)handle; list_addToSelection(l,i,*a); } /* * void list_selectAll(list l,list_action a) * * Use * Selects all the items in a list * * Parameters * list l == the list * list_action a == what to do with the icons (list_READSTATE ain't all * that useful, and list_TOGGLESTATE is downright wierd). */ void list_selectAll(list l,list_action a) { list_doForItems(l,list__sel,&a); } /* * int list_numSelected(list l) * * Use * Informs the caller how many items are selected. * * Parameters * list l == the list handle * * Returns * An integer indicating the number of selected items */ int list_numSelected(list l) { return (l->nsel); } /* * int list_itemToIndex(list l,list_item i) * * Use * Translates a list_item into the index of the item. This avoids * assumptions about the mapping of indices to item numbers. In the * future, for example, the list_item data type may be used as a pointer to * the list item data structure in memory. Most of the time this will be * irrelevant anyway. * * Parameters * list l == the list handle * list_item i == the list item to translate * * Returns * An integer giving the index of the item. The first item has index 0, as * for C arrays. */ int list_itemToIndex(list l,list_item i) { int ind=0; list_item itm=l->list; while (itm) { if (itm==i) return (ind); itm=itm->next; ind++; } return (-1); } /* * list_item list_indexToItem(list l,int index) * * Use * Performs the reverse operation to the previous routine. It will * translate an index to a list_item. * * Parameters * list l == the list handle * int index == the index of the item required * * Returns * The equivalent list_item for the item. */ list_item list_indexToItem(list l,int index) { int ind=0; list_item itm=l->list; while (itm) { if (ind==index) return (itm); itm=itm->next; ind++; } return (list_NOITEM); } /* * list_item list_helpItem(list l) * * Use * Returns the item that Help is interested in. * * Parameters * list l == the list's handle * * Returns * A list_item */ list_item list_helpItem(list l) { wimp_eventstr *e=wimpt_last_event(); if (help_wasHelp()) return (list__coordsToItem ( e->data.msg.data.helprequest.m.x, e->data.msg.data.helprequest.m.y,l )); else werr(TRUE,msgs_lookup("listHIE:(list_helpItem, caller fault): " "Not called on HELPREQUEST event.")); return (0); }