/*

Directory Opus 4
Original GPL release version 4.12
Copyright 1993-2000 Jonathan Potter

This program 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
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

All users of Directory Opus 4 (including versions distributed
under the GPL) are entitled to upgrade to the latest version of
Directory Opus version 5 at a reduced price. Please see
http://www.gpsoft.com.au for more information.

The release of Directory Opus 4 under the GPL in NO WAY affects
the existing commercial status of Directory Opus 5.

*/

#include "dopuslib.h"

#define LIST_IDBASE 32767

#define GAD_SLIDER 0
#define GAD_UP     1
#define GAD_DOWN   2

extern char nullstring[];
//int _FPERR,_SIGFPE;

void DisplayView(struct DOpusListView *);
void dohilite(struct DOpusListView *,int);
void savepens(struct DOpusListView *);
void restorepens(struct DOpusListView *);
int scroll_view(struct DOpusListView *,int,int *,int);
int view_valid(struct DOpusListView *,int);

char nullstring[]="                                                                                                                                ";

__saveds DoAddListView(register struct DOpusListView *view __asm("a0"),
  register int count __asm("d0"))
{
  struct RastPort *rp;
  int a,addcount=0;

  while (view && (addcount<count)) {
    view->key=NULL; view->selected=NULL;
    view->gadadd=0; view->chk=view->itemselected;
    if (view->items)
      for (view->count=0;view->items[view->count] &&
        (!(view->flags&DLVF_ENDNL) || view->items[view->count][0]);view->count++);
    else view->count=0;

    if (!(view->listgads=(struct Gadget *)DoAllocRemember(&view->key,sizeof(struct Gadget)*3,MEMF_CLEAR)) ||
      !(view->listimage=(struct Image *)DoAllocRemember(&view->key,sizeof(struct Image),MEMF_CLEAR)) ||
      !(view->listprop=(struct PropInfo *)DoAllocRemember(&view->key,sizeof(struct PropInfo),MEMF_CLEAR)) ||
      !(view->selected=(char *)DoAllocRemember(&view->key,view->count,MEMF_CLEAR))) {
      DoFreeRemember(&view->key);
      break;
    }
    if (view->selectarray) CopyMem(view->selectarray,view->selected,view->count);
    if (view->slidercol==-1) view->slidercol=1;
    if (view->sliderbgcol==-1) view->slidercol=0;
    if (view->textcol==-1) view->textcol=1;
    if (view->boxhi==-1) view->boxhi=1;
    if (view->boxlo==-1) view->boxlo=2;
    if (view->arrowfg==-1) view->arrowfg=1;
    if (view->arrowbg==-1) view->arrowbg=0;
    if (view->itemfg==-1) view->itemfg=1;
    if (view->itembg==-1) view->itembg=0;
    rp=view->window->RPort;
    view->fw=rp->Font->tf_XSize;
    view->fh=rp->Font->tf_YSize;
    if (view->fh<8) view->fh=8;
    view->fb=rp->Font->tf_Baseline;
    view->ty=(view->fh-8)/2;
    view->lines=view->h/view->fh;
    view->columns=view->w/view->fw;
    if (view->columns>128) view->columns=128;
    view->yo=view->y+((view->h-(view->lines*view->fh))/2);
    view->xo=view->x+((view->w-(view->columns*view->fw))/2);
    if (view->flags&DLVF_CHECK) {
      view->xo+=22;
      view->columns=(view->w-22)/view->fw;
    }
    if (view->topitem>(view->count-view->lines)) view->topitem=view->count-view->lines;
    if (view->topitem<0) view->topitem=0;

    savepens(view);
    SetDrMd(rp,JAM2);
    if (view->flags&DLVF_DUMB)
      Do3DBox(rp,view->x,view->y,view->w,view->h,view->boxlo,view->boxhi);
    else Do3DBox(rp,view->x,view->y,view->w,view->h,view->boxhi,view->boxlo);
    Do3DBox(rp,view->x+view->w+4,view->y,view->sliderwidth+4,view->h-16,view->boxhi,view->boxlo);
    DoArrow(rp,view->x+view->w+4,view->y+view->h-14,view->sliderwidth+4,6,view->arrowfg,view->arrowbg,0);
    Do3DBox(rp,view->x+view->w+4,view->y+view->h-14,view->sliderwidth+4,6,view->boxhi,view->boxlo);
    DoArrow(rp,view->x+view->w+4,view->y+view->h-6,view->sliderwidth+4,6,view->arrowfg,view->arrowbg,1);
    Do3DBox(rp,view->x+view->w+4,view->y+view->h-6,view->sliderwidth+4,6,view->boxhi,view->boxlo);
    if (view->title) {
      SetAPen(rp,view->textcol);
      a=strlen(view->title);
      if (view->flags&DLVF_TTOP) Move(rp,view->x,(view->y-view->fh-2)+view->fb);
      else Move(rp,view->x-6-(a*view->fw),view->yo+view->fb);
      Text(rp,view->title,a);
    }
    view->listimage->Width=view->sliderwidth; view->listimage->Height=view->h-18;
    view->listimage->Depth=1; view->listimage->PlaneOnOff=view->slidercol;
    view->listprop->Flags=FREEVERT|PROPBORDERLESS;
    view->listprop->VertBody=0xffff;
    view->listgads[0].NextGadget=&view->listgads[1];
    view->listgads[0].LeftEdge=view->x+view->w+6;
    view->listgads[0].TopEdge=view->y+1;
    view->listgads[0].Width=view->sliderwidth;
    view->listgads[0].Height=view->h-18;
    view->listgads[0].Flags=GADGHNONE;
    view->listgads[0].Activation=GADGIMMEDIATE|RELVERIFY|FOLLOWMOUSE;
    view->listgads[0].GadgetType=PROPGADGET;
    view->listgads[0].GadgetRender=(APTR)view->listimage;
    view->listgads[0].MutualExclude=view->sliderbgcol;
    view->listgads[0].SpecialInfo=(APTR)view->listprop;
    view->listgads[0].GadgetID=LIST_IDBASE+(view->listid*3);
    view->listgads[1].LeftEdge=view->x+view->w+2;
    view->listgads[1].TopEdge=view->y+view->h-15;
    view->listgads[1].Width=view->sliderwidth+8;
    view->listgads[1].Height=8;
    view->listgads[1].Flags=GADGHCOMP;
    view->listgads[1].Activation=GADGIMMEDIATE|RELVERIFY;
    view->listgads[1].GadgetType=BOOLGADGET;
    view->listgads[1].GadgetID=LIST_IDBASE+(view->listid*3)+1;
    CopyMem((char *)&view->listgads[1],(char *)&view->listgads[2],sizeof(struct Gadget));
    view->listgads[1].NextGadget=&view->listgads[2];
    view->listgads[2].TopEdge+=8;
    view->listgads[2].GadgetID++;
    if (view->flags&DLVF_HIREC)
      DoAddGadgetBorders(&view->key,&view->listgads[1],2,view->boxhi,view->boxlo);
    AddGList(view->window,view->listgads,-1,3,NULL);
    view->gadadd=3;
    view->mx=view->xo+(view->columns*view->fw)-1;
    view->my=view->yo+(view->lines*view->fh)-1;
    view->oldoffset=-1;
    restorepens(view);
    DoFixSliderBody(view->window,&view->listgads[0],view->count,view->lines,0);
    DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,2);
    DisplayView(view);
    view=view->next;
    ++addcount;
  }
  return(addcount);
}

void __stdargs __saveds DoFixSliderBody(struct Window *win,
  struct Gadget *gad,
  int count,
  int lines,
  int show)
{
  USHORT body,gh,ih,min;
  struct Image *image;
  struct PropInfo *pinfo;
  float div;
  int vh,oh;

  pinfo=(struct PropInfo *)gad->SpecialInfo;
  if (pinfo->Flags&FREEVERT) {
    vh=0;
    gh=gad->Height;
    min=KNOBVMIN;
  }
  else {
    vh=1;
    gh=gad->Width;
    min=KNOBHMIN;
  }
  if (count<=lines) body=0xffff;
  else {
    body=((float)0x7fff)/(((float)count)/((float)lines));
    body<<=1;
  }
  image=(struct Image *)gad->GadgetRender;
  if (body==0) ih=min;
  else {
    div=(float)0xffff/(float)body;
    if (div==0) div=1;
    ih=(int)((float)((float)gh/div));
    if (ih<min) ih=min;
  }
  if (vh) pinfo->HorizBody=body;
  else pinfo->VertBody=body;
  if (pinfo->Flags&AUTOKNOB) {
    if (show && win)
      NewModifyProp(gad,win,NULL,pinfo->Flags,pinfo->HorizPot,pinfo->VertPot,
        pinfo->HorizBody,pinfo->VertBody,1);
  }
  else {
    if (vh) {
      oh=image->Width; image->Width=ih;
    }
    else {
      oh=image->Height; image->Height=ih;
    }
    if (show && win && (oh!=ih || show==2)) DoShowSlider(win,gad);
  }
}

void __stdargs __saveds DoFixSliderPot(struct Window *win,
  struct Gadget *gad,
  int off,
  int count,
  int lines,
  int show)
{
  USHORT vert,vh,gh,ih,te,oh;
  float div;
  struct Image *image;
  struct PropInfo *pinfo;

  image=(struct Image *)gad->GadgetRender;
  pinfo=(struct PropInfo *)gad->SpecialInfo;
  if (pinfo->Flags&FREEVERT) {
    vh=0;
    gh=gad->Height; ih=image->Height;
  }
  else {
    vh=1;
    gh=gad->Width; ih=image->Width;
  }

  if (count<=lines) vert=0;
  else vert=(off*0xffff)/(count-lines);
  if (vert==0) te=0;
  else {
    div=(float)0xffff/(float)vert;
    if (div==0) div=1;
    te=(int)((float)((float)(gh-ih)/div));
  }
  if (vh) pinfo->HorizPot=vert;
  else pinfo->VertPot=vert;
  if (pinfo->Flags&AUTOKNOB) {
    if (show && win)
      NewModifyProp(gad,win,NULL,pinfo->Flags,pinfo->HorizPot,pinfo->VertPot,
        pinfo->HorizBody,pinfo->VertBody,1);
  }
  else {
    if (vh) {
      oh=image->LeftEdge; image->LeftEdge=te;
    }
    else {
      oh=image->TopEdge; image->TopEdge=te;
    }
    if (show && win && (oh!=te || show==2)) DoShowSlider(win,gad);
  }
}

void __saveds DoShowSlider(register struct Window *win __asm("a0"),
  register struct Gadget *gad __asm("a1"))
{
  int ob,ot,y,old_pen,old_mode;
  struct Image *image;
  struct PropInfo *pinfo;
  struct RastPort *r;

  pinfo=(struct PropInfo *)gad->SpecialInfo;

  if (pinfo->Flags&AUTOKNOB) {
    RefreshGList(gad,win,NULL,1);
    return;
  }

  image=(struct Image *)gad->GadgetRender;

  r=win->RPort;
  old_pen=r->FgPen;
  old_mode=r->DrawMode;

  SetAPen(r,gad->MutualExclude);
  SetDrMd(r,JAM1);

  if (pinfo->Flags&FREEVERT) {
    ob=image->TopEdge+image->Height;
    ot=image->TopEdge; y=gad->LeftEdge+gad->Width+1;
    if (ot>=0) RectFill(r,gad->LeftEdge-2,gad->TopEdge-1,y,gad->TopEdge+ot-1);
    if (ob<=gad->Height) RectFill(r,gad->LeftEdge-2,gad->TopEdge+ob,y,gad->TopEdge+gad->Height);
    if (gad->MutualExclude) {
      RectFill(r,gad->LeftEdge-2,gad->TopEdge+ot,gad->LeftEdge-1,gad->TopEdge+ob);
      RectFill(r,y-1,gad->TopEdge+ot,y,gad->TopEdge+ob);
    }
  }
  else {
    ob=image->LeftEdge+image->Width;
    ot=image->LeftEdge; y=gad->TopEdge+gad->Height+1;
    if (ot>=0) RectFill(r,gad->LeftEdge-2,gad->TopEdge-1,gad->LeftEdge+ot-1,y-1);
    if (ob<=gad->Width) RectFill(r,gad->LeftEdge+ob,gad->TopEdge-1,gad->LeftEdge+gad->Width+1,y-1);
    if (gad->MutualExclude) {
      RectFill(r,gad->LeftEdge+ot,gad->TopEdge-1,gad->LeftEdge+ob,gad->TopEdge-1);
      RectFill(r,gad->LeftEdge+ot,y-1,gad->LeftEdge+ob,y-1);
    }
  }
  DrawImage(r,image,gad->LeftEdge,gad->TopEdge);

  SetAPen(r,old_pen);
  SetDrMd(r,old_mode);
}

void DisplayView(view)
struct DOpusListView *view;
{
  struct RastPort *rp;
  int y,a,b,top,bot,dif,dir,start,end,step,w;
  char buf[128];
  static UWORD ditherdata[2]={0x8888,0x2222};

  savepens(view);
  if (view->oldoffset==-1 || (dif=(view->oldoffset-view->topitem))>=view->lines || dif<=-view->lines) {
    top=view->topitem;
    bot=view->topitem+view->lines-1;
    dir=0;
  }
  else if (dif<0) {
    top=view->topitem+view->lines+dif;
    bot=view->topitem+view->lines-1;
    dir=view->fh;
  }
  else if (dif>0) {
    top=view->topitem;
    bot=view->topitem+dif-1;
    dir=-view->fh;
  }
  else return;
  rp=view->window->RPort;
  SetAPen(rp,view->itemfg); SetBPen(rp,view->itembg);
  SetDrMd(rp,JAM2);
  start=view->topitem; end=view->topitem+view->lines; step=1;
  if (dir>0) y=view->yo+view->fb+(view->fh*(view->lines-1));
  else {
    y=view->yo+view->fb;
    if (dir) {
      start=end-1; end=view->topitem-1; step=-1;
    }
  }
  if (!dir && view->flags&DLVF_CHECK) ScrollRaster(rp,0,view->lines*view->fh,view->x,view->yo,view->xo-1,view->my);
  w=view->w-(view->xo-view->x);
  for (a=start;a!=end;a+=step) {
    if (a>=top && a<=bot) {
      CopyMem(nullstring,buf,view->columns);
      if (view->items && a<view->count && view->items[a] &&
        (!(view->flags&DLVF_ENDNL) || view->items[a][0])) {
        b=strlen(view->items[a]); if (b>view->columns) b=view->columns;
        CopyMem(view->items[a],buf,b);
      }
      Move(rp,view->xo,y);
      if (dir) {
        if (dir<0) ClipBlit(rp,view->xo,view->yo,rp,view->xo,view->yo+view->fh,
          w,(view->lines-1)*view->fh,0xc0);
        else ClipBlit(rp,view->xo,view->yo+view->fh,rp,view->xo,view->yo,
          w,(view->lines-1)*view->fh,0xc0);
        if (view->flags&DLVF_CHECK) ScrollRaster(rp,0,dir,view->x,view->yo,view->xo-1,view->my);
      }
      Text(rp,buf,view->columns);
      if (view->selectarray && view->selectarray[a]&LVARRAY_DISABLED) {
        rp->AreaPtrn=ditherdata; rp->AreaPtSz=1;
        SetDrMd(rp,JAM1);
        SetAPen(rp,view->itembg);
        RectFill(rp,view->xo,y-view->fb,rp->cp_x-1,(y-view->fb)+view->fh-1);
        SetAPen(rp,view->itemfg);
        SetDrMd(rp,JAM2);
        rp->AreaPtrn=NULL; rp->AreaPtSz=0;
      }
      if (a<view->count) {
        if ((view->flags&DLVF_MULTI && view->selected[a]&LVARRAY_SELECTED) ||
          (view->flags&DLVF_LEAVE && view->itemselected==a)) {
          if (!(view->flags&DLVF_TOGGLE) || view->chk==view->itemselected) {
            if (view->flags&DLVF_CHECK) DrawCheckMark(rp,view->xo-18,y+view->ty-view->fb,1);
            else {
              SetDrMd(rp,COMPLEMENT);
              if (dir<0) b=0;
              else if (dir>0) b=view->lines-1;
              else b=a-view->topitem;
              dohilite(view,b);
              SetDrMd(rp,JAM2);
            }
          }
        }
      }
    }
    if (!dir) y+=view->fh;
  }
  view->oldoffset=view->topitem;
  restorepens(view);
}

__stdargs __saveds DoGetSliderPos(struct Gadget *gad,
  int count,
  int lines)
{
  int i;
  USHORT vertpot;
  struct PropInfo *pinfo;
  float div;

  pinfo=(struct PropInfo *)gad->SpecialInfo;
  if (pinfo->Flags&FREEVERT) vertpot=pinfo->VertPot;
  else vertpot=pinfo->HorizPot;

  if (count<lines || vertpot==0) return(0);
  div=(float)0xffff/(float)vertpot;
  if (div==0) div=1;
  i=(int)((float)((float)((count-lines)+1)/div));
  if (i>(count-lines)) i=count-lines;
  if (i<0) i=0;
  return(i);
}

struct DOpusListView * __saveds
  DoListViewIDCMP(
    register struct DOpusListView *view __asm("a0"),
    register struct IntuiMessage *imsg __asm("a1"))
{
  int gadgetid,list,x,y,rep,xo,histate=0,offset,itemnum,newoffset,lastout=0,temp;
  ULONG class,idcmpflags;
  USHORT code;

  class=imsg->Class;
  code=imsg->Code;
  idcmpflags=view->window->IDCMPFlags;

  if (class==GADGETUP || class==GADGETDOWN) {
    gadgetid=((struct Gadget *)imsg->IAddress)->GadgetID;
    if (gadgetid<LIST_IDBASE) return((struct DOpusListView *)-1);
    gadgetid-=LIST_IDBASE; list=gadgetid/3;
    gadgetid%=3;
    while (view) {
      if (view->listid==list && view->window==imsg->IDCMPWindow) break;
      view=view->next;
    }
    if (!view) return((struct DOpusListView *)-1);
    ReplyMsg((struct Message *)imsg);

    if (!(idcmpflags&IDCMP_MOUSEMOVE)) ModifyIDCMP(view->window,idcmpflags|IDCMP_MOUSEMOVE);

    switch (gadgetid) {
      case GAD_SLIDER:
        view->topitem=DoGetSliderPos(&view->listgads[0],view->count,view->lines);
        DisplayView(view);
        if (view->sliderbgcol) DoShowSlider(view->window,&view->listgads[0]);
        if (class==IDCMP_GADGETDOWN) {
          FOREVER {
            Wait(1<<view->window->UserPort->mp_SigBit);
            while (imsg=(struct IntuiMessage *)GetMsg(view->window->UserPort)) {
              class=imsg->Class;
              ReplyMsg((struct Message *)imsg);
              if (class==IDCMP_MOUSEMOVE) {
                view->topitem=DoGetSliderPos(&view->listgads[0],view->count,view->lines);
                if (view->sliderbgcol) DoShowSlider(view->window,&view->listgads[0]);
                DisplayView(view);
              }
              else if (class==IDCMP_GADGETUP) break;
            }
            if (class==IDCMP_GADGETUP) break;
          }
          view->topitem=DoGetSliderPos(&view->listgads[0],view->count,view->lines);
          if (view->sliderbgcol) DoShowSlider(view->window,&view->listgads[0]);
          DisplayView(view);
        }
        break;

      case GAD_UP:
        if (view->topitem==0) break;
        --view->topitem;
      case GAD_DOWN:
        if (gadgetid==GAD_DOWN) {
          if (view->topitem>view->count-(view->lines+1)) break;
          ++view->topitem;
        }
        DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,1);
        DisplayView(view);
        Delay(5);
        FOREVER {
          if (imsg=(struct IntuiMessage *)GetMsg(view->window->UserPort)) {
            class=imsg->Class; code=imsg->Code;
            ReplyMsg((struct Message *)imsg);
            if (class==IDCMP_GADGETUP || (class==IDCMP_MOUSEBUTTONS && code==SELECTUP))
              break;
          }
          if (gadgetid==GAD_UP) {
            if (view->topitem==0) break;
            --view->topitem;
          }
          else {
            if (view->topitem>view->count-(view->lines+1)) break;
            ++view->topitem;
          }
          DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,1);
          DisplayView(view);
          if (view->flags&DLVF_SLOW) Delay(1);
          else WaitTOF();
        }
        break;
    }
    ModifyIDCMP(view->window,idcmpflags);
    return(NULL);
  }
  else if (class==IDCMP_MOUSEBUTTONS && code==SELECTDOWN) {
    x=imsg->MouseX;
    y=imsg->MouseY;

    while (view) {
      if (view->window==imsg->IDCMPWindow && !(view->flags&DLVF_DUMB)) {
        if (view->flags&DLVF_CHECK) xo=view->xo-22;
        else xo=view->xo;
        if (x>=xo && x<view->mx && y>=view->yo && y<view->my) break;
      }
      view=view->next;
    }
    if (!view) return((struct DOpusListView *)-1);
    ReplyMsg((struct Message *)imsg);

    offset=(y-view->yo)/view->fh;
    itemnum=offset+view->topitem;
    if (itemnum>=view->count) {
      itemnum=view->count-1;
      offset=itemnum-view->topitem;
      if (offset<0) return(NULL);
    }

    ModifyIDCMP(view->window,idcmpflags|IDCMP_MOUSEBUTTONS|IDCMP_MOUSEMOVE|IDCMP_INTUITICKS);
    if (!(rep=view->window->Flags&WFLG_REPORTMOUSE))
      view->window->Flags|=WFLG_REPORTMOUSE;

    savepens(view);
    if (view_valid(view,itemnum)) {
      dohilite(view,offset);
      histate=1;
    }

    FOREVER {
      while (imsg=(struct IntuiMessage *)GetMsg(view->window->UserPort)) {
        class=imsg->Class;
        code=imsg->Code;
        x=imsg->MouseX;
        y=imsg->MouseY;
        ReplyMsg((struct Message *)imsg);

        if (class==IDCMP_MOUSEBUTTONS) {
          if (code==SELECTUP) break;
          if (code==MENUUP) {
            if (histate) {
              histate=0;
              dohilite(view,offset);
            }
            break;
          }
        }
        else if (class==IDCMP_INTUITICKS) {
          if ((newoffset=((y-view->yo)/view->fh))!=offset) {
            newoffset=scroll_view(view,newoffset,&histate,offset);
            if (newoffset>=0 && newoffset<view->lines) {
              offset=newoffset;
              temp=itemnum;
              itemnum=view->topitem+offset;
              if (itemnum!=temp && view_valid(view,itemnum)) {
                histate=1;
                dohilite(view,offset);
              }
            }
          }
        }
        else if (class==IDCMP_MOUSEMOVE) {
          if ((newoffset=((y-view->yo)/view->fh))!=offset || x<xo || x>=view->mx || y<view->yo) {
            if (y<view->yo || y>view->yo+view->h) {
              if (lastout) continue;
              lastout=1;
            }
            else lastout=0;
            if (view->count<view->lines &&
              newoffset>=view->count &&
              offset>=view->count-1 && histate) continue;
            if (histate) {
              histate=0;
              dohilite(view,offset);
            }
            if (x<xo || x>=view->mx) continue;
            newoffset=scroll_view(view,newoffset,&histate,0);
            if (newoffset>=0 && newoffset<view->lines) {
              offset=newoffset;
              itemnum=view->topitem+offset;
              if (view_valid(view,itemnum)) {
                histate=1;
                dohilite(view,offset);
              }
            }
          }
          else if (!histate) {
            if (view_valid(view,itemnum)) {
              histate=1;
              dohilite(view,offset);
            }
          }
        }
      }
      if (class==IDCMP_MOUSEBUTTONS && (code==SELECTUP || code==MENUUP)) break;
      Wait(1<<view->window->UserPort->mp_SigBit);
    }

    if (histate) {
      if (view->flags&DLVF_MULTI) {
        view->selected[itemnum]^=LVARRAY_SELECTED;
        if (view->flags&DLVF_CHECK) {
          dohilite(view,offset);
          SetAPen(view->window->RPort,view->itemfg);
          DrawCheckMark(view->window->RPort,
            view->xo-18,
            view->yo+(view->fh*offset)+view->ty,
            (view->selected[itemnum]&LVARRAY_SELECTED));
        }
      }
      else if (view->flags&DLVF_LEAVE) {
        dohilite(view,offset);
        SetAPen(view->window->RPort,view->itemfg);
        if (view->itemselected==itemnum) {
          if (view->flags&DLVF_TOGGLE) {
            if (view->chk==view->itemselected) {
              if (view->flags&DLVF_CHECK) {
                DrawCheckMark(view->window->RPort,
                  view->xo-18,
                  view->yo+(view->fh*offset)+view->ty,
                  0);
              }
              else dohilite(view,offset);
              view->chk=-1;
            }
            else {
              if (view->flags&DLVF_CHECK) {
                DrawCheckMark(view->window->RPort,
                  view->xo-18,
                  view->yo+(view->fh*offset)+view->ty,
                  1);
              }
              else dohilite(view,offset);
              view->chk=view->itemselected;
            }
          }
        }
        else {
          if (view->flags&DLVF_CHECK) {
            DrawCheckMark(view->window->RPort,
              view->xo-18,
              view->yo+(view->fh*offset)+view->ty,
              1);
          }
          else dohilite(view,offset);
          if (view->chk>-1) {
            y=view->chk-view->topitem;
            if (y>=0 && y<view->lines) {
              if (view->flags&DLVF_CHECK) {
                DrawCheckMark(view->window->RPort,
                  view->xo-18,
                  view->yo+(view->fh*y)+view->ty,
                  0);
              }
              else dohilite(view,y);
            }
          }
          view->chk=itemnum;
        }
      }
      else dohilite(view,offset);
    }
    if (!rep) view->window->Flags&=~WFLG_REPORTMOUSE;
    ModifyIDCMP(view->window,idcmpflags);
    restorepens(view);
    if (histate) {
      view->itemselected=itemnum;
      return(view);
    }
    return(NULL);
  }
  return((struct DOpusListView *)-1);
}

void dohilite(view,a)
struct DOpusListView *view;
int a;
{
  int x,mode;

  mode=view->window->RPort->DrawMode;
  SetDrMd(view->window->RPort,COMPLEMENT);
  if (view->flags&DLVF_CHECK) x=view->xo-22;
  else x=view->xo;
  RectFill(view->window->RPort,x,view->yo+(view->fh*a),view->mx,view->yo+(view->fh*(a+1))-1);
  SetDrMd(view->window->RPort,mode);
}

void savepens(view)
struct DOpusListView *view;
{
  view->ofg=view->window->RPort->FgPen;
  view->obg=view->window->RPort->BgPen;
  view->odm=view->window->RPort->DrawMode;
}

void restorepens(view)
struct DOpusListView *view;
{
  SetAPen(view->window->RPort,view->ofg);
  SetBPen(view->window->RPort,view->obg);
  SetDrMd(view->window->RPort,view->odm);
}

__saveds DoRefreshListView(register struct DOpusListView *view __asm("a0"),
  register int count __asm("d0"))
{
  int realcount=0;

  while (view && realcount<count) {
    if (view->items)
      for (view->count=0;view->items[view->count] &&
        (!(view->flags&DLVF_ENDNL) || view->items[view->count][0]);view->count++);
    else view->count=0;
    if (view->selectarray) {
      if (view->selected=(char *)DoAllocRemember(&view->key,view->count,MEMF_CLEAR))
        CopyMem(view->selectarray,view->selected,view->count);
    }
    if (view->topitem>(view->count-view->lines)) view->topitem=view->count-view->lines;
    if (view->topitem<0) view->topitem=0;
    view->chk=view->itemselected;
    DoFixSliderBody(view->window,&view->listgads[0],view->count,view->lines,0);
    DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,2);
    view->oldoffset=-1;
    DisplayView(view);
    view=view->next;
    ++realcount;
  }
  return(realcount);
}

__saveds DoRemoveListView(register struct DOpusListView *view __asm("a0"),
  register int count __asm("d0"))
{
  int realcount=0;

  while (view && realcount<count) {
    if (view->gadadd) RemoveGList(view->window,view->listgads,view->gadadd);
    DoFreeRemember(&view->key);
    view=view->next;
    ++realcount;
  }
  return(realcount);
}

scroll_view(view,offset,histate,oldoffset)
struct DOpusListView *view;
int offset,*histate,oldoffset;
{
  int draw=0;

  if (view->count<view->lines && offset>=view->count)
    return(view->count-1);

  if (offset<0) {
    if (view->topitem>0) {
      --view->topitem;
      draw=1;
    }
    offset=0;
  }
  else if (offset>=view->lines) {
    if (view->topitem<=view->count-(view->lines+1)) {
      ++view->topitem;
      draw=1;
    }
    offset=view->lines-1;
  }

  if (draw) {
    if (*histate) {
      *histate=0;
      dohilite(view,oldoffset);
    }
    DoFixSliderPot(view->window,&view->listgads[0],view->topitem,view->count,view->lines,1);
    DisplayView(view);
  }
  return(offset);
}

view_valid(view,itemnum)
struct DOpusListView *view;
int itemnum;
{
  if (itemnum<view->count &&
    (!view->selectarray || !(view->selectarray[itemnum]&LVARRAY_DISABLED)))
    return(1);
  return(0);
}
