home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / DOpus4-GPL / Library / listview.c < prev    next >
C/C++ Source or Header  |  2000-01-27  |  24KB  |  806 lines

  1. /*
  2.  
  3. Directory Opus 4
  4. Original GPL release version 4.12
  5. Copyright 1993-2000 Jonathan Potter
  6.  
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20.  
  21. All users of Directory Opus 4 (including versions distributed
  22. under the GPL) are entitled to upgrade to the latest version of
  23. Directory Opus version 5 at a reduced price. Please see
  24. http://www.gpsoft.com.au for more information.
  25.  
  26. The release of Directory Opus 4 under the GPL in NO WAY affects
  27. the existing commercial status of Directory Opus 5.
  28.  
  29. */
  30.  
  31. #include "dopuslib.h"
  32.  
  33. #define LIST_IDBASE 32767
  34.  
  35. #define GAD_SLIDER 0
  36. #define GAD_UP     1
  37. #define GAD_DOWN   2
  38.  
  39. extern char nullstring[];
  40. //int _FPERR,_SIGFPE;
  41.  
  42. void DisplayView(struct DOpusListView *);
  43. void dohilite(struct DOpusListView *,int);
  44. void savepens(struct DOpusListView *);
  45. void restorepens(struct DOpusListView *);
  46. scroll_view(struct DOpusListView *,int,int *,int);
  47. view_valid(struct DOpusListView *,int);
  48.  
  49. char nullstring[]="                                                                                                                                ";
  50.  
  51. __asm __saveds DoAddListView(register __a0 struct DOpusListView *view,
  52.     register __d0 int count)
  53. {
  54.     struct RastPort *rp;
  55.     int a,addcount=0;
  56.  
  57.     while (view && (addcount<count)) {
  58.         view->key=NULL; view->selected=NULL;
  59.         view->gadadd=0; view->chk=view->itemselected;
  60.         if (view->items)
  61.             for (view->count=0;view->items[view->count] &&
  62.                 (!(view->flags&DLVF_ENDNL) || view->items[view->count][0]);view->count++);
  63.         else view->count=0;
  64.  
  65.         if (!(view->listgads=(struct Gadget *)DoAllocRemember(&view->key,sizeof(struct Gadget)*3,MEMF_CLEAR)) ||
  66.             !(view->listimage=(struct Image *)DoAllocRemember(&view->key,sizeof(struct Image),MEMF_CLEAR)) ||
  67.             !(view->listprop=(struct PropInfo *)DoAllocRemember(&view->key,sizeof(struct PropInfo),MEMF_CLEAR)) ||
  68.             !(view->selected=(char *)DoAllocRemember(&view->key,view->count,MEMF_CLEAR))) {
  69.             DoFreeRemember(&view->key);
  70.             break;
  71.         }
  72.         if (view->selectarray) CopyMem(view->selectarray,view->selected,view->count);
  73.         if (view->slidercol==-1) view->slidercol=1;
  74.         if (view->sliderbgcol==-1) view->slidercol=0;
  75.         if (view->textcol==-1) view->textcol=1;
  76.         if (view->boxhi==-1) view->boxhi=1;
  77.         if (view->boxlo==-1) view->boxlo=2;
  78.         if (view->arrowfg==-1) view->arrowfg=1;
  79.         if (view->arrowbg==-1) view->arrowbg=0;
  80.         if (view->itemfg==-1) view->itemfg=1;
  81.         if (view->itembg==-1) view->itembg=0;
  82.         rp=view->window->RPort;
  83.         view->fw=rp->Font->tf_XSize;
  84.         view->fh=rp->Font->tf_YSize;
  85.         if (view->fh<8) view->fh=8;
  86.         view->fb=rp->Font->tf_Baseline;
  87.         view->ty=(view->fh-8)/2;
  88.         view->lines=view->h/view->fh;
  89.         view->columns=view->w/view->fw;
  90.         if (view->columns>128) view->columns=128;
  91.         view->yo=view->y+((view->h-(view->lines*view->fh))/2);
  92.         view->xo=view->x+((view->w-(view->columns*view->fw))/2);
  93.         if (view->flags&DLVF_CHECK) {
  94.             view->xo+=22;
  95.             view->columns=(view->w-22)/view->fw;
  96.         }
  97.         if (view->topitem>(view->count-view->lines)) view->topitem=view->count-view->lines;
  98.         if (view->topitem<0) view->topitem=0;
  99.  
  100.         savepens(view);
  101.         SetDrMd(rp,JAM2);
  102.         if (view->flags&DLVF_DUMB)
  103.             Do3DBox(rp,view->x,view->y,view->w,view->h,view->boxlo,view->boxhi);
  104.         else Do3DBox(rp,view->x,view->y,view->w,view->h,view->boxhi,view->boxlo);
  105.         Do3DBox(rp,view->x+view->w+4,view->y,view->sliderwidth+4,view->h-16,view->boxhi,view->boxlo);
  106.         DoArrow(rp,view->x+view->w+4,view->y+view->h-14,view->sliderwidth+4,6,view->arrowfg,view->arrowbg,0);
  107.         Do3DBox(rp,view->x+view->w+4,view->y+view->h-14,view->sliderwidth+4,6,view->boxhi,view->boxlo);
  108.         DoArrow(rp,view->x+view->w+4,view->y+view->h-6,view->sliderwidth+4,6,view->arrowfg,view->arrowbg,1);
  109.         Do3DBox(rp,view->x+view->w+4,view->y+view->h-6,view->sliderwidth+4,6,view->boxhi,view->boxlo);
  110.         if (view->title) {
  111.             SetAPen(rp,view->textcol);
  112.             a=strlen(view->title);
  113.             if (view->flags&DLVF_TTOP) Move(rp,view->x,(view->y-view->fh-2)+view->fb);
  114.             else Move(rp,view->x-6-(a*view->fw),view->yo+view->fb);
  115.             Text(rp,view->title,a);
  116.         }
  117.         view->listimage->Width=view->sliderwidth; view->listimage->Height=view->h-18;
  118.         view->listimage->Depth=1; view->listimage->PlaneOnOff=view->slidercol;
  119.         view->listprop->Flags=FREEVERT|PROPBORDERLESS;
  120.         view->listprop->VertBody=0xffff;
  121.         view->listgads[0].NextGadget=&view->listgads[1];
  122.         view->listgads[0].LeftEdge=view->x+view->w+6;
  123.         view->listgads[0].TopEdge=view->y+1;
  124.         view->listgads[0].Width=view->sliderwidth;
  125.         view->listgads[0].Height=view->h-18;
  126.         view->listgads[0].Flags=GADGHNONE;
  127.         view->listgads[0].Activation=GADGIMMEDIATE|RELVERIFY|FOLLOWMOUSE;
  128.         view->listgads[0].GadgetType=PROPGADGET;
  129.         view->listgads[0].GadgetRender=(APTR)view->listimage;
  130.         view->listgads[0].MutualExclude=view->sliderbgcol;
  131.         view->listgads[0].SpecialInfo=(APTR)view->listprop;
  132.         view->listgads[0].GadgetID=LIST_IDBASE+(view->listid*3);
  133.         view->listgads[1].LeftEdge=view->x+view->w+2;
  134.         view->listgads[1].TopEdge=view->y+view->h-15;
  135.         view->listgads[1].Width=view->sliderwidth+8;
  136.         view->listgads[1].Height=8;
  137.         view->listgads[1].Flags=GADGHCOMP;
  138.         view->listgads[1].Activation=GADGIMMEDIATE|RELVERIFY;
  139.         view->listgads[1].GadgetType=BOOLGADGET;
  140.         view->listgads[1].GadgetID=LIST_IDBASE+(view->listid*3)+1;
  141.         CopyMem((char *)&view->listgads[1],(char *)&view->listgads[2],sizeof(struct Gadget));
  142.         view->listgads[1].NextGadget=&view->listgads[2];
  143.         view->listgads[2].TopEdge+=8;
  144.         view->listgads[2].GadgetID++;
  145.         if (view->flags&DLVF_HIREC)
  146.             DoAddGadgetBorders(&view->key,&view->listgads[1],2,view->boxhi,view->boxlo);
  147.         AddGList(view->window,view->listgads,-1,3,NULL);
  148.         view->gadadd=3;
  149.         view->mx=view->xo+(view->columns*view->fw)-1;
  150.         view->my=view->yo+(view->lines*view->fh)-1;
  151.         view->oldoffset=-1;
  152.         restorepens(view);
  153.         DoFixSliderBody(view->window,&view->listgads[0],view->count,view->lines,0);
  154.         DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,2);
  155.         DisplayView(view);
  156.         view=view->next;
  157.         ++addcount;
  158.     }
  159.     return(addcount);
  160. }
  161.  
  162. void __stdargs __saveds DoFixSliderBody(struct Window *win,
  163.     struct Gadget *gad,
  164.     int count,
  165.     int lines,
  166.     int show)
  167. {
  168.     USHORT body,gh,ih,min;
  169.     struct Image *image;
  170.     struct PropInfo *pinfo;
  171.     float div;
  172.     int vh,oh;
  173.  
  174.     pinfo=(struct PropInfo *)gad->SpecialInfo;
  175.     if (pinfo->Flags&FREEVERT) {
  176.         vh=0;
  177.         gh=gad->Height;
  178.         min=KNOBVMIN;
  179.     }
  180.     else {
  181.         vh=1;
  182.         gh=gad->Width;
  183.         min=KNOBHMIN;
  184.     }
  185.     if (count<=lines) body=0xffff;
  186.     else {
  187.         body=((float)0x7fff)/(((float)count)/((float)lines));
  188.         body<<=1;
  189.     }
  190.     image=(struct Image *)gad->GadgetRender;
  191.     if (body==0) ih=min;
  192.     else {
  193.         div=(float)0xffff/(float)body;
  194.         if (div==0) div=1;
  195.         ih=(int)((float)((float)gh/div));
  196.         if (ih<min) ih=min;
  197.     }
  198.     if (vh) pinfo->HorizBody=body;
  199.     else pinfo->VertBody=body;
  200.     if (pinfo->Flags&AUTOKNOB) {
  201.         if (show && win)
  202.             NewModifyProp(gad,win,NULL,pinfo->Flags,pinfo->HorizPot,pinfo->VertPot,
  203.                 pinfo->HorizBody,pinfo->VertBody,1);
  204.     }
  205.     else {
  206.         if (vh) {
  207.             oh=image->Width; image->Width=ih;
  208.         }
  209.         else {
  210.             oh=image->Height; image->Height=ih;
  211.         }
  212.         if (show && win && (oh!=ih || show==2)) DoShowSlider(win,gad);
  213.     }
  214. }
  215.  
  216. void __stdargs __saveds DoFixSliderPot(struct Window *win,
  217.     struct Gadget *gad,
  218.     int off,
  219.     int count,
  220.     int lines,
  221.     int show)
  222. {
  223.     USHORT vert,vh,gh,ih,te,oh;
  224.     float div;
  225.     struct Image *image;
  226.     struct PropInfo *pinfo;
  227.  
  228.     image=(struct Image *)gad->GadgetRender;
  229.     pinfo=(struct PropInfo *)gad->SpecialInfo;
  230.     if (pinfo->Flags&FREEVERT) {
  231.         vh=0;
  232.         gh=gad->Height; ih=image->Height;
  233.     }
  234.     else {
  235.         vh=1;
  236.         gh=gad->Width; ih=image->Width;
  237.     }
  238.  
  239.     if (count<=lines) vert=0;
  240.     else vert=(off*0xffff)/(count-lines);
  241.     if (vert==0) te=0;
  242.     else {
  243.         div=(float)0xffff/(float)vert;
  244.         if (div==0) div=1;
  245.         te=(int)((float)((float)(gh-ih)/div));
  246.     }
  247.     if (vh) pinfo->HorizPot=vert;
  248.     else pinfo->VertPot=vert;
  249.     if (pinfo->Flags&AUTOKNOB) {
  250.         if (show && win)
  251.             NewModifyProp(gad,win,NULL,pinfo->Flags,pinfo->HorizPot,pinfo->VertPot,
  252.                 pinfo->HorizBody,pinfo->VertBody,1);
  253.     }
  254.     else {
  255.         if (vh) {
  256.             oh=image->LeftEdge; image->LeftEdge=te;
  257.         }
  258.         else {
  259.             oh=image->TopEdge; image->TopEdge=te;
  260.         }
  261.         if (show && win && (oh!=te || show==2)) DoShowSlider(win,gad);
  262.     }
  263. }
  264.  
  265. void __asm __saveds DoShowSlider(register __a0 struct Window *win,
  266.     register __a1 struct Gadget *gad)
  267. {
  268.     int ob,ot,y,old_pen,old_mode;
  269.     struct Image *image;
  270.     struct PropInfo *pinfo;
  271.     struct RastPort *r;
  272.  
  273.     pinfo=(struct PropInfo *)gad->SpecialInfo;
  274.  
  275.     if (pinfo->Flags&AUTOKNOB) {
  276.         RefreshGList(gad,win,NULL,1);
  277.         return;
  278.     }
  279.  
  280.     image=(struct Image *)gad->GadgetRender;
  281.  
  282.     r=win->RPort;
  283.     old_pen=r->FgPen;
  284.     old_mode=r->DrawMode;
  285.  
  286.     SetAPen(r,gad->MutualExclude);
  287.     SetDrMd(r,JAM1);
  288.  
  289.     if (pinfo->Flags&FREEVERT) {
  290.         ob=image->TopEdge+image->Height;
  291.         ot=image->TopEdge; y=gad->LeftEdge+gad->Width+1;
  292.         if (ot>=0) RectFill(r,gad->LeftEdge-2,gad->TopEdge-1,y,gad->TopEdge+ot-1);
  293.         if (ob<=gad->Height) RectFill(r,gad->LeftEdge-2,gad->TopEdge+ob,y,gad->TopEdge+gad->Height);
  294.         if (gad->MutualExclude) {
  295.             RectFill(r,gad->LeftEdge-2,gad->TopEdge+ot,gad->LeftEdge-1,gad->TopEdge+ob);
  296.             RectFill(r,y-1,gad->TopEdge+ot,y,gad->TopEdge+ob);
  297.         }
  298.     }
  299.     else {
  300.         ob=image->LeftEdge+image->Width;
  301.         ot=image->LeftEdge; y=gad->TopEdge+gad->Height+1;
  302.         if (ot>=0) RectFill(r,gad->LeftEdge-2,gad->TopEdge-1,gad->LeftEdge+ot-1,y-1);
  303.         if (ob<=gad->Width) RectFill(r,gad->LeftEdge+ob,gad->TopEdge-1,gad->LeftEdge+gad->Width+1,y-1);
  304.         if (gad->MutualExclude) {
  305.             RectFill(r,gad->LeftEdge+ot,gad->TopEdge-1,gad->LeftEdge+ob,gad->TopEdge-1);
  306.             RectFill(r,gad->LeftEdge+ot,y-1,gad->LeftEdge+ob,y-1);
  307.         }
  308.     }
  309.     DrawImage(r,image,gad->LeftEdge,gad->TopEdge);
  310.  
  311.     SetAPen(r,old_pen);
  312.     SetDrMd(r,old_mode);
  313. }
  314.  
  315. void DisplayView(view)
  316. struct DOpusListView *view;
  317. {
  318.     struct RastPort *rp;
  319.     int y,a,b,top,bot,dif,dir,start,end,step,w;
  320.     char buf[128];
  321.     static UWORD ditherdata[2]={0x8888,0x2222};
  322.  
  323.     savepens(view);
  324.     if (view->oldoffset==-1 || (dif=(view->oldoffset-view->topitem))>=view->lines || dif<=-view->lines) {
  325.         top=view->topitem;
  326.         bot=view->topitem+view->lines-1;
  327.         dir=0;
  328.     }
  329.     else if (dif<0) {
  330.         top=view->topitem+view->lines+dif;
  331.         bot=view->topitem+view->lines-1;
  332.         dir=view->fh;
  333.     }
  334.     else if (dif>0) {
  335.         top=view->topitem;
  336.         bot=view->topitem+dif-1;
  337.         dir=-view->fh;
  338.     }
  339.     else return;
  340.     rp=view->window->RPort;
  341.     SetAPen(rp,view->itemfg); SetBPen(rp,view->itembg);
  342.     SetDrMd(rp,JAM2);
  343.     start=view->topitem; end=view->topitem+view->lines; step=1;
  344.     if (dir>0) y=view->yo+view->fb+(view->fh*(view->lines-1));
  345.     else {
  346.         y=view->yo+view->fb;
  347.         if (dir) {
  348.             start=end-1; end=view->topitem-1; step=-1;
  349.         }
  350.     }
  351.     if (!dir && view->flags&DLVF_CHECK) ScrollRaster(rp,0,view->lines*view->fh,view->x,view->yo,view->xo-1,view->my);
  352.     w=view->w-(view->xo-view->x);
  353.     for (a=start;a!=end;a+=step) {
  354.         if (a>=top && a<=bot) {
  355.             CopyMem(nullstring,buf,view->columns);
  356.             if (view->items && a<view->count && view->items[a] &&
  357.                 (!(view->flags&DLVF_ENDNL) || view->items[a][0])) {
  358.                 b=strlen(view->items[a]); if (b>view->columns) b=view->columns;
  359.                 CopyMem(view->items[a],buf,b);
  360.             }
  361.             Move(rp,view->xo,y);
  362.             if (dir) {
  363.                 if (dir<0) ClipBlit(rp,view->xo,view->yo,rp,view->xo,view->yo+view->fh,
  364.                     w,(view->lines-1)*view->fh,0xc0);
  365.                 else ClipBlit(rp,view->xo,view->yo+view->fh,rp,view->xo,view->yo,
  366.                     w,(view->lines-1)*view->fh,0xc0);
  367.                 if (view->flags&DLVF_CHECK) ScrollRaster(rp,0,dir,view->x,view->yo,view->xo-1,view->my);
  368.             }
  369.             Text(rp,buf,view->columns);
  370.             if (view->selectarray && view->selectarray[a]&LVARRAY_DISABLED) {
  371.                 rp->AreaPtrn=ditherdata; rp->AreaPtSz=1;
  372.                 SetDrMd(rp,JAM1);
  373.                 SetAPen(rp,view->itembg);
  374.                 RectFill(rp,view->xo,y-view->fb,rp->cp_x-1,(y-view->fb)+view->fh-1);
  375.                 SetAPen(rp,view->itemfg);
  376.                 SetDrMd(rp,JAM2);
  377.                 rp->AreaPtrn=NULL; rp->AreaPtSz=0;
  378.             }
  379.             if (a<view->count) {
  380.                 if ((view->flags&DLVF_MULTI && view->selected[a]&LVARRAY_SELECTED) ||
  381.                     (view->flags&DLVF_LEAVE && view->itemselected==a)) {
  382.                     if (!(view->flags&DLVF_TOGGLE) || view->chk==view->itemselected) {
  383.                         if (view->flags&DLVF_CHECK) DrawCheckMark(rp,view->xo-18,y+view->ty-view->fb,1);
  384.                         else {
  385.                             SetDrMd(rp,COMPLEMENT);
  386.                             if (dir<0) b=0;
  387.                             else if (dir>0) b=view->lines-1;
  388.                             else b=a-view->topitem;
  389.                             dohilite(view,b);
  390.                             SetDrMd(rp,JAM2);
  391.                         }
  392.                     }
  393.                 }
  394.             }
  395.         }
  396.         if (!dir) y+=view->fh;
  397.     }
  398.     view->oldoffset=view->topitem;
  399.     restorepens(view);
  400. }
  401.  
  402. __stdargs __saveds DoGetSliderPos(struct Gadget *gad,
  403.     int count,
  404.     int lines)
  405. {
  406.     int i;
  407.     USHORT vertpot;
  408.     struct PropInfo *pinfo;
  409.     float div;
  410.  
  411.     pinfo=(struct PropInfo *)gad->SpecialInfo;
  412.     if (pinfo->Flags&FREEVERT) vertpot=pinfo->VertPot;
  413.     else vertpot=pinfo->HorizPot;
  414.  
  415.     if (count<lines || vertpot==0) return(0);
  416.     div=(float)0xffff/(float)vertpot;
  417.     if (div==0) div=1;
  418.     i=(int)((float)((float)((count-lines)+1)/div));
  419.     if (i>(count-lines)) i=count-lines;
  420.     if (i<0) i=0;
  421.     return(i);
  422. }
  423.  
  424. struct DOpusListView *__asm __saveds
  425.     DoListViewIDCMP(
  426.         register __a0 struct DOpusListView *view,
  427.         register __a1 struct IntuiMessage *imsg)
  428. {
  429.     int gadgetid,list,x,y,rep,xo,histate=0,offset,itemnum,newoffset,lastout=0,temp;
  430.     ULONG class,idcmpflags;
  431.     USHORT code;
  432.  
  433.     class=imsg->Class;
  434.     code=imsg->Code;
  435.     idcmpflags=view->window->IDCMPFlags;
  436.  
  437.     if (class==GADGETUP || class==GADGETDOWN) {
  438.         gadgetid=((struct Gadget *)imsg->IAddress)->GadgetID;
  439.         if (gadgetid<LIST_IDBASE) return((struct DOpusListView *)-1);
  440.         gadgetid-=LIST_IDBASE; list=gadgetid/3;
  441.         gadgetid%=3;
  442.         while (view) {
  443.             if (view->listid==list && view->window==imsg->IDCMPWindow) break;
  444.             view=view->next;
  445.         }
  446.         if (!view) return((struct DOpusListView *)-1);
  447.         ReplyMsg((struct Message *)imsg);
  448.  
  449.         if (!(idcmpflags&IDCMP_MOUSEMOVE)) ModifyIDCMP(view->window,idcmpflags|IDCMP_MOUSEMOVE);
  450.  
  451.         switch (gadgetid) {
  452.             case GAD_SLIDER:
  453.                 view->topitem=DoGetSliderPos(&view->listgads[0],view->count,view->lines);
  454.                 DisplayView(view);
  455.                 if (view->sliderbgcol) DoShowSlider(view->window,&view->listgads[0]);
  456.                 if (class==IDCMP_GADGETDOWN) {
  457.                     FOREVER {
  458.                         Wait(1<<view->window->UserPort->mp_SigBit);
  459.                         while (imsg=(struct IntuiMessage *)GetMsg(view->window->UserPort)) {
  460.                             class=imsg->Class;
  461.                             ReplyMsg((struct Message *)imsg);
  462.                             if (class==IDCMP_MOUSEMOVE) {
  463.                                 view->topitem=DoGetSliderPos(&view->listgads[0],view->count,view->lines);
  464.                                 if (view->sliderbgcol) DoShowSlider(view->window,&view->listgads[0]);
  465.                                 DisplayView(view);
  466.                             }
  467.                             else if (class==IDCMP_GADGETUP) break;
  468.                         }
  469.                         if (class==IDCMP_GADGETUP) break;
  470.                     }
  471.                     view->topitem=DoGetSliderPos(&view->listgads[0],view->count,view->lines);
  472.                     if (view->sliderbgcol) DoShowSlider(view->window,&view->listgads[0]);
  473.                     DisplayView(view);
  474.                 }
  475.                 break;
  476.  
  477.             case GAD_UP:
  478.                 if (view->topitem==0) break;
  479.                 --view->topitem;
  480.             case GAD_DOWN:
  481.                 if (gadgetid==GAD_DOWN) {
  482.                     if (view->topitem>view->count-(view->lines+1)) break;
  483.                     ++view->topitem;
  484.                 }
  485.                 DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,1);
  486.                 DisplayView(view);
  487.                 Delay(5);
  488.                 FOREVER {
  489.                     if (imsg=(struct IntuiMessage *)GetMsg(view->window->UserPort)) {
  490.                         class=imsg->Class; code=imsg->Code;
  491.                         ReplyMsg((struct Message *)imsg);
  492.                         if (class==IDCMP_GADGETUP || (class==IDCMP_MOUSEBUTTONS && code==SELECTUP))
  493.                             break;
  494.                     }
  495.                     if (gadgetid==GAD_UP) {
  496.                         if (view->topitem==0) break;
  497.                         --view->topitem;
  498.                     }
  499.                     else {
  500.                         if (view->topitem>view->count-(view->lines+1)) break;
  501.                         ++view->topitem;
  502.                     }
  503.                     DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,1);
  504.                     DisplayView(view);
  505.                     if (view->flags&DLVF_SLOW) Delay(1);
  506.                     else WaitTOF();
  507.                 }
  508.                 break;
  509.         }
  510.         ModifyIDCMP(view->window,idcmpflags);
  511.         return(NULL);
  512.     }
  513.     else if (class==IDCMP_MOUSEBUTTONS && code==SELECTDOWN) {
  514.         x=imsg->MouseX;
  515.         y=imsg->MouseY;
  516.  
  517.         while (view) {
  518.             if (view->window==imsg->IDCMPWindow && !(view->flags&DLVF_DUMB)) {
  519.                 if (view->flags&DLVF_CHECK) xo=view->xo-22;
  520.                 else xo=view->xo;
  521.                 if (x>=xo && x<view->mx && y>=view->yo && y<view->my) break;
  522.             }
  523.             view=view->next;
  524.         }
  525.         if (!view) return((struct DOpusListView *)-1);
  526.         ReplyMsg((struct Message *)imsg);
  527.  
  528.         offset=(y-view->yo)/view->fh;
  529.         itemnum=offset+view->topitem;
  530.         if (itemnum>=view->count) {
  531.             itemnum=view->count-1;
  532.             offset=itemnum-view->topitem;
  533.             if (offset<0) return(NULL);
  534.         }
  535.  
  536.         ModifyIDCMP(view->window,idcmpflags|IDCMP_MOUSEBUTTONS|IDCMP_MOUSEMOVE|IDCMP_INTUITICKS);
  537.         if (!(rep=view->window->Flags&WFLG_REPORTMOUSE))
  538.             view->window->Flags|=WFLG_REPORTMOUSE;
  539.  
  540.         savepens(view);
  541.         if (view_valid(view,itemnum)) {
  542.             dohilite(view,offset);
  543.             histate=1;
  544.         }
  545.  
  546.         FOREVER {
  547.             while (imsg=(struct IntuiMessage *)GetMsg(view->window->UserPort)) {
  548.                 class=imsg->Class;
  549.                 code=imsg->Code;
  550.                 x=imsg->MouseX;
  551.                 y=imsg->MouseY;
  552.                 ReplyMsg((struct Message *)imsg);
  553.  
  554.                 if (class==IDCMP_MOUSEBUTTONS) {
  555.                     if (code==SELECTUP) break;
  556.                     if (code==MENUUP) {
  557.                         if (histate) {
  558.                             histate=0;
  559.                             dohilite(view,offset);
  560.                         }
  561.                         break;
  562.                     }
  563.                 }
  564.                 else if (class==IDCMP_INTUITICKS) {
  565.                     if ((newoffset=((y-view->yo)/view->fh))!=offset) {
  566.                         newoffset=scroll_view(view,newoffset,&histate,offset);
  567.                         if (newoffset>=0 && newoffset<view->lines) {
  568.                             offset=newoffset;
  569.                             temp=itemnum;
  570.                             itemnum=view->topitem+offset;
  571.                             if (itemnum!=temp && view_valid(view,itemnum)) {
  572.                                 histate=1;
  573.                                 dohilite(view,offset);
  574.                             }
  575.                         }
  576.                     }
  577.                 }
  578.                 else if (class==IDCMP_MOUSEMOVE) {
  579.                     if ((newoffset=((y-view->yo)/view->fh))!=offset || x<xo || x>=view->mx || y<view->yo) {
  580.                         if (y<view->yo || y>view->yo+view->h) {
  581.                             if (lastout) continue;
  582.                             lastout=1;
  583.                         }
  584.                         else lastout=0;
  585.                         if (view->count<view->lines &&
  586.                             newoffset>=view->count &&
  587.                             offset>=view->count-1 && histate) continue;
  588.                         if (histate) {
  589.                             histate=0;
  590.                             dohilite(view,offset);
  591.                         }
  592.                         if (x<xo || x>=view->mx) continue;
  593.                         newoffset=scroll_view(view,newoffset,&histate,0);
  594.                         if (newoffset>=0 && newoffset<view->lines) {
  595.                             offset=newoffset;
  596.                             itemnum=view->topitem+offset;
  597.                             if (view_valid(view,itemnum)) {
  598.                                 histate=1;
  599.                                 dohilite(view,offset);
  600.                             }
  601.                         }
  602.                     }
  603.                     else if (!histate) {
  604.                         if (view_valid(view,itemnum)) {
  605.                             histate=1;
  606.                             dohilite(view,offset);
  607.                         }
  608.                     }
  609.                 }
  610.             }
  611.             if (class==IDCMP_MOUSEBUTTONS && (code==SELECTUP || code==MENUUP)) break;
  612.             Wait(1<<view->window->UserPort->mp_SigBit);
  613.         }
  614.  
  615.         if (histate) {
  616.             if (view->flags&DLVF_MULTI) {
  617.                 view->selected[itemnum]^=LVARRAY_SELECTED;
  618.                 if (view->flags&DLVF_CHECK) {
  619.                     dohilite(view,offset);
  620.                     SetAPen(view->window->RPort,view->itemfg);
  621.                     DrawCheckMark(view->window->RPort,
  622.                         view->xo-18,
  623.                         view->yo+(view->fh*offset)+view->ty,
  624.                         (view->selected[itemnum]&LVARRAY_SELECTED));
  625.                 }
  626.             }
  627.             else if (view->flags&DLVF_LEAVE) {
  628.                 dohilite(view,offset);
  629.                 SetAPen(view->window->RPort,view->itemfg);
  630.                 if (view->itemselected==itemnum) {
  631.                     if (view->flags&DLVF_TOGGLE) {
  632.                         if (view->chk==view->itemselected) {
  633.                             if (view->flags&DLVF_CHECK) {
  634.                                 DrawCheckMark(view->window->RPort,
  635.                                     view->xo-18,
  636.                                     view->yo+(view->fh*offset)+view->ty,
  637.                                     0);
  638.                             }
  639.                             else dohilite(view,offset);
  640.                             view->chk=-1;
  641.                         }
  642.                         else {
  643.                             if (view->flags&DLVF_CHECK) {
  644.                                 DrawCheckMark(view->window->RPort,
  645.                                     view->xo-18,
  646.                                     view->yo+(view->fh*offset)+view->ty,
  647.                                     1);
  648.                             }
  649.                             else dohilite(view,offset);
  650.                             view->chk=view->itemselected;
  651.                         }
  652.                     }
  653.                 }
  654.                 else {
  655.                     if (view->flags&DLVF_CHECK) {
  656.                         DrawCheckMark(view->window->RPort,
  657.                             view->xo-18,
  658.                             view->yo+(view->fh*offset)+view->ty,
  659.                             1);
  660.                     }
  661.                     else dohilite(view,offset);
  662.                     if (view->chk>-1) {
  663.                         y=view->chk-view->topitem;
  664.                         if (y>=0 && y<view->lines) {
  665.                             if (view->flags&DLVF_CHECK) {
  666.                                 DrawCheckMark(view->window->RPort,
  667.                                     view->xo-18,
  668.                                     view->yo+(view->fh*y)+view->ty,
  669.                                     0);
  670.                             }
  671.                             else dohilite(view,y);
  672.                         }
  673.                     }
  674.                     view->chk=itemnum;
  675.                 }
  676.             }
  677.             else dohilite(view,offset);
  678.         }
  679.         if (!rep) view->window->Flags&=~WFLG_REPORTMOUSE;
  680.         ModifyIDCMP(view->window,idcmpflags);
  681.         restorepens(view);
  682.         if (histate) {
  683.             view->itemselected=itemnum;
  684.             return(view);
  685.         }
  686.         return(NULL);
  687.     }
  688.     return((struct DOpusListView *)-1);
  689. }
  690.  
  691. void dohilite(view,a)
  692. struct DOpusListView *view;
  693. int a;
  694. {
  695.     int x,mode;
  696.  
  697.     mode=view->window->RPort->DrawMode;
  698.     SetDrMd(view->window->RPort,COMPLEMENT);
  699.     if (view->flags&DLVF_CHECK) x=view->xo-22;
  700.     else x=view->xo;
  701.     RectFill(view->window->RPort,x,view->yo+(view->fh*a),view->mx,view->yo+(view->fh*(a+1))-1);
  702.     SetDrMd(view->window->RPort,mode);
  703. }
  704.  
  705. void savepens(view)
  706. struct DOpusListView *view;
  707. {
  708.     view->ofg=view->window->RPort->FgPen;
  709.     view->obg=view->window->RPort->BgPen;
  710.     view->odm=view->window->RPort->DrawMode;
  711. }
  712.  
  713. void restorepens(view)
  714. struct DOpusListView *view;
  715. {
  716.     SetAPen(view->window->RPort,view->ofg);
  717.     SetBPen(view->window->RPort,view->obg);
  718.     SetDrMd(view->window->RPort,view->odm);
  719. }
  720.  
  721. __asm __saveds DoRefreshListView(register __a0 struct DOpusListView *view,
  722.     register __d0 int count)
  723. {
  724.     int realcount=0;
  725.  
  726.     while (view && realcount<count) {
  727.         if (view->items)
  728.             for (view->count=0;view->items[view->count] &&
  729.                 (!(view->flags&DLVF_ENDNL) || view->items[view->count][0]);view->count++);
  730.         else view->count=0;
  731.         if (view->selectarray) {
  732.             if (view->selected=(char *)DoAllocRemember(&view->key,view->count,MEMF_CLEAR))
  733.                 CopyMem(view->selectarray,view->selected,view->count);
  734.         }
  735.         if (view->topitem>(view->count-view->lines)) view->topitem=view->count-view->lines;
  736.         if (view->topitem<0) view->topitem=0;
  737.         view->chk=view->itemselected;
  738.         DoFixSliderBody(view->window,&view->listgads[0],view->count,view->lines,0);
  739.         DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,2);
  740.         view->oldoffset=-1;
  741.         DisplayView(view);
  742.         view=view->next;
  743.         ++realcount;
  744.     }
  745.     return(realcount);
  746. }
  747.  
  748. __asm __saveds DoRemoveListView(register __a0 struct DOpusListView *view,
  749.     register __d0 int count)
  750. {
  751.     int realcount=0;
  752.  
  753.     while (view && realcount<count) {
  754.         if (view->gadadd) RemoveGList(view->window,view->listgads,view->gadadd);
  755.         DoFreeRemember(&view->key);
  756.         view=view->next;
  757.         ++realcount;
  758.     }
  759.     return(realcount);
  760. }
  761.  
  762. scroll_view(view,offset,histate,oldoffset)
  763. struct DOpusListView *view;
  764. int offset,*histate,oldoffset;
  765. {
  766.     int draw=0;
  767.  
  768.     if (view->count<view->lines && offset>=view->count)
  769.         return(view->count-1);
  770.  
  771.     if (offset<0) {
  772.         if (view->topitem>0) {
  773.             --view->topitem;
  774.             draw=1;
  775.         }
  776.         offset=0;
  777.     }
  778.     else if (offset>=view->lines) {
  779.         if (view->topitem<=view->count-(view->lines+1)) {
  780.             ++view->topitem;
  781.             draw=1;
  782.         }
  783.         offset=view->lines-1;
  784.     }
  785.  
  786.     if (draw) {
  787.         if (*histate) {
  788.             *histate=0;
  789.             dohilite(view,oldoffset);
  790.         }
  791.         DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,1);
  792.         DisplayView(view);
  793.     }
  794.     return(offset);
  795. }
  796.  
  797. view_valid(view,itemnum)
  798. struct DOpusListView *view;
  799. int itemnum;
  800. {
  801.     if (itemnum<view->count &&
  802.         (!view->selectarray || !(view->selectarray[itemnum]&LVARRAY_DISABLED)))
  803.         return(1);
  804.     return(0);
  805. }
  806.