[comp.sources.x] v10i085: xv - display and manipulate images, Part07/10

bradley@halibut.cis.upenn.edu (John Bradley) (11/28/90)

Submitted-by: bradley@halibut.cis.upenn.edu (John Bradley)
Posting-number: Volume 10, Issue 85
Archive-name: xv/part07

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./xvbutt.c`
then
echo "writting ./xvbutt.c"
cat > ./xvbutt.c << '\BARFOO\'
/* 
 * xvbutt.c - regular and 'radio' pushbuttons
 *
 * callable functions:
 *
 *   BTCreate()             -  create a button
 *   BTSetActive()          -  change 'active' status of button
 *   BTRedraw()             -  redraw button
 *   BTTrack()              -  clicked in button.  track until mouse up
 *
 *   RBCreate()             -  create an RBUTT and append to supplied list
 *   RBRedraw()             -  redraw one or all RBUTTs in a list
 *   RBSelect()             -  change selected item in list of RBUTTs
 *   RBWhich()              -  returns index of selected RBUTT in list
 *   RBCount()              -  returns # of RBUTTs in list
 *   RBSetActive()          -  sets active status of an RBUTT
 *   RBClick()              -  finds clicked-on rb in a list
 *   RBTrack()              -  tracks rb after click, until release
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */


#include "xv.h"
#include "bitmaps.h"

static int    rbpixmade = 0;
static Pixmap rbon, rboff, rbon1, rboff1;

#ifdef __STDC__
static void drawRB(RBUTT *);
#else
static void drawRB();
#endif

/**********************************************/
void BTCreate(bp,win,x,y,w,h,str,fg,bg)
BUTT         *bp;
Window        win;
int           x,y,w,h;
char         *str;
unsigned long fg,bg;
{
  bp->win = win;
  bp->x = x;  bp->y = y;  bp->w = w;  bp->h = h;
  bp->str = str;
  bp->fg = fg;  bp->bg = bg;
  bp->lit = 0;
  bp->active = 1;
  bp->toggle = 0;
}



/**********************************************/
void BTSetActive(bp,act)
BUTT         *bp;
int           act;
{
  if (bp->active != act) {
    bp->active = act;
    BTRedraw(bp);
  }
}



/**********************************************/
void BTRedraw(bp)
BUTT *bp;
{
  int x,y,w,h,r;
  XPoint poly[9];

  x = bp->x;  y=bp->y;  w=bp->w;  h=bp->h;  r=3;

  /* set up the polygon */
  poly[0].x = x;      poly[0].y = y+r;
  poly[1].x = x;      poly[1].y = y+h-r;
  poly[2].x = x+r;    poly[2].y = y+h;
  poly[3].x = x+w-r;  poly[3].y = y+h;
  poly[4].x = x+w;    poly[4].y = y+h-r;
  poly[5].x = x+w;    poly[5].y = y+r;
  poly[6].x = x+w-r;  poly[6].y = y;
  poly[7].x = x+r;    poly[7].y = y;
  poly[8].x = x;      poly[8].y = y+r;


  if (!bp->active) bp->lit = 0;   /* sanity assertion */

  if (bp->lit) XSetForeground(theDisp, theGC, bp->fg);
          else XSetForeground(theDisp, theGC, bp->bg);
  XFillPolygon(theDisp,bp->win,theGC,poly,9,Convex,CoordModeOrigin);

  XSetForeground(theDisp, theGC, bp->fg);
  XDrawLines(theDisp,bp->win,theGC,poly,9,CoordModeOrigin);

  if (!bp->active) {   /* stipple the text if not active */
    XSetFillStyle(theDisp, theGC, FillStippled);
    XSetStipple(theDisp, theGC, grayStip);
  }

  if (bp->lit) XSetForeground(theDisp, theGC, bp->bg);
          else XSetForeground(theDisp, theGC, bp->fg);
  XDrawString(theDisp, bp->win, theGC, CENTERX(mfinfo,x+w/2,bp->str),
	      CENTERY(mfinfo,y+h/2), bp->str, strlen(bp->str));

  if (!bp->active) XSetFillStyle(theDisp,theGC,FillSolid);  /* back to norm */
}



/**********************************************/
int BTTrack(bp)
BUTT *bp;
{
  /* called when we've gotten a click inside 'bp'.  returns 1 if button
     was still selected lit when mouse was released. */

  Window       rW, cW;
  int          x, y, rx, ry, rval, inval;
  unsigned int mask;

  if (!bp->active) return 0;   /* inactive button */

  bp->lit = !bp->lit;
  inval = bp->lit;

  BTRedraw(bp);  XFlush(theDisp);
  Timer(75);  /* long enough for turn on to be visible */

  while (XQueryPointer(theDisp,bp->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
    if (!(mask & Button1Mask)) break;    /* button released */

    if (bp->lit!=inval && PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) {
      bp->lit = inval;  BTRedraw(bp);  XFlush(theDisp);
    }
    
    if (bp->lit==inval && !PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) {
      bp->lit = !inval;  BTRedraw(bp);  XFlush(theDisp);
    }
  }

  rval = (bp->lit == inval);
  
  if (bp->lit && !bp->toggle) 
    { bp->lit = 0;  BTRedraw(bp);  XFlush(theDisp); }

  return(rval);
}








/***********************************************/
RBUTT *RBCreate(rblist, win, x,y,str, fg, bg)
      RBUTT        *rblist;
      Window        win;
      int           x,y;
      char         *str;
      unsigned long fg,bg;
{
  /* mallocs an RBUTT, fills in the fields, and appends it to rblist
     if rblist is NULL, this is the first rb in the list.  It will
     be made the 'selected' one 

     Note: no need to check return status.  It'll fatal error if it 
     can't malloc */

  RBUTT *rb, *rbptr;

  rb = (RBUTT *) malloc(sizeof(RBUTT));
  if (!rb) FatalError("couldn't malloc RBUTT");

  /* fill in the fields of the structure */
  rb->win      = win;
  rb->x        = x;
  rb->y        = y;
  rb->str      = str;
  rb->selected = 0;
  rb->active   = 1;
  rb->next     = (RBUTT *) NULL;
  rb->fg       = fg;
  rb->bg       = bg;

  if (rblist) {            /* append to end of list */
    rbptr = rblist;
    while (rbptr->next) rbptr = rbptr->next;
    rbptr->next = rb;
  }
  else {                   /* this is the first one in the list.  select it */
    rb->selected = 1;
  }


  /* and, on an unrelated note, if the RB pixmaps haven't been created yet,
     do so.  We'll be needing them, y'see... */

  if (!rbpixmade) {
    rbon  = XCreatePixmapFromBitmapData(theDisp, rootW, rb_on_bits,
	     rb_on_width, rb_on_height, fg, bg, dispDEEP);

    rboff = XCreatePixmapFromBitmapData(theDisp, rootW, rb_off_bits,
	     rb_off_width, rb_off_height, fg, bg, dispDEEP);
    rbon1 = XCreatePixmapFromBitmapData(theDisp, rootW, rb_on1_bits,
	     rb_on1_width, rb_on1_height, fg, bg, dispDEEP);
    rboff1= XCreatePixmapFromBitmapData(theDisp, rootW, rb_off1_bits,
	     rb_off1_width, rb_off1_height, fg, bg, dispDEEP);

    rbpixmade = 1;
  }

  return(rb);
}
  



/***********************************************/
void RBRedraw(rblist, num)
RBUTT *rblist;
int    num;
{
  /* redraws the 'num-th' RB in the list.  if num < 0, redraws entire list */

  RBUTT *rb;
  int    i;

  /* point 'rb' at the appropriate RBUTT, *if* we're not drawing entire list */
  if (num>=0) {
    i=0;  rb=rblist;
    while (i!=num && rb) { rb = rb->next;  i++; }
    if (!rb) return;                     /* num is out of range.  do nothing */
    drawRB(rb);
  }

  else {                                 /* draw entire list */
    rb = rblist;
    while (rb) {
      drawRB(rb);
      rb = rb->next;
    }
  }
}


static void drawRB(rb)
RBUTT *rb;
{
  /* draws the rb being pointed at */

  if (!rb) return;  /* rb = NULL */

  XSetForeground(theDisp, theGC, rb->fg);
  XSetBackground(theDisp, theGC, rb->bg);

  if (rb->selected) 
    XCopyArea(theDisp, rbon, rb->win, theGC, 0, 0, rb_on_width, rb_on_height, 
	      rb->x, rb->y);
  else
    XCopyArea(theDisp, rboff, rb->win, theGC, 0, 0, rb_on_width, rb_on_height, 
	      rb->x, rb->y);

  XDrawString(theDisp, rb->win, theGC, rb->x+rb_on_width+4, 
	      rb->y+rb_on_height/2 - CHIGH/2 + ASCENT,rb->str,strlen(rb->str));

  /* if non-active, dim button and string */
  if (!rb->active) { 
    /* stipple the RB by drawing 'bg' where there's 1's in the stipple */
    XSetFillStyle(theDisp, theGC, FillStippled);
    XSetStipple(theDisp, theGC, grayStip);
    XSetForeground(theDisp, theGC, rb->bg);
    XFillRectangle(theDisp,rb->win,theGC,rb->x,rb->y,rb_on_width,rb_on_height);
    XFillRectangle(theDisp,rb->win,theGC, rb->x + rb_on_width+4,
		   rb->y+rb_on_height/2 - CHIGH/2, StringWidth(rb->str),CHIGH);
    XSetFillStyle(theDisp, theGC, FillSolid);
  }
}


/***********************************************/
void RBSelect(rblist, n)
RBUTT *rblist;
int    n;
{
  RBUTT *rbold, *rb;
  int    i;

  /* makes rb #n the selected rb in the list.  Does all redrawing.  Does
     nothing if rb already selected */

  /* get pointers to the currently selected rb and the desired rb */
  rbold = rblist;
  while (rbold && !rbold->selected) rbold = rbold->next;
  if (!rbold) return;    /* no currently selected item.  shouldn't happen */

  rb = rblist;  i=0;
  while (rb && i!=n) {rb = rb->next;  i++; }
  if (!rb) return;    /* 'n' is out of range */


  if (rb == rbold) return;   /* 'n' is already selected.  do nothing */

  rbold->selected = 0;
  rb->selected    = 1;
  drawRB(rbold);
  drawRB(rb);
}


	      
/***********************************************/
int RBWhich(rblist)
RBUTT *rblist;
{
  int i;

  /* returns index of currently selected rb.  if none, returns -1 */

  i = 0;
  while (rblist && !rblist->selected) { rblist = rblist->next;  i++; }

  if (!rblist) return -1;             /* didn't find one */
  return i;
}


/***********************************************/
int RBCount(rblist)
RBUTT *rblist;
{
  int i;

  /* returns # of rb's in the list */

  i = 0;
  while (rblist) { rblist = rblist->next; i++; }
  return i;
}


/***********************************************/
void RBSetActive(rblist, n, act)
RBUTT *rblist;
int n,act;
{
  RBUTT *rb;
  int    i;

  /* sets 'active' status of rb #n.  does redrawing */

  rb=rblist;  i=0;
  while (rb && i!=n) { rb = rb->next; i++; }
  if (!rb) return;                         /* n out of range.  do nothing */

  if (rb->active != act) {
    rb->active = act;
    drawRB(rb);
  }
}


/***********************************************/
int RBClick(rblist, mx, my)
RBUTT *rblist;
int    mx,my;
{
  int i;

  /* searches through rblist to see if mouse click at mx,my is in the
     clickable region of any of the rb's.  If it finds one, it returns 
     it's index in the list.  If not, returns -1 */

  i = 0;
  while (rblist) {
    if (PTINRECT(mx, my, rblist->x, rblist->y, rb_on_width, rb_on_height)) 
      break;
    rblist = rblist->next;
    i++;
  }

  if (!rblist) return -1;
  return(i);
}


/***********************************************/
void RBTrack(rblist, n)
RBUTT *rblist;
int    n;
{
  RBUTT       *rb;
  Window       rW, cW;
  int          i, x, y, rx, ry, lit;
  unsigned int mask;
  Pixmap litpix, darkpix;

  rb=rblist;  i=0;
  while (rb && i!=n) { rb = rb->next; i++; }
  if (!rb) return;                    /* n out of range */

  /* called once we've figured out that the mouse clicked in 'rb' */

  if (!rb->active) return;

  if (rb->selected) { litpix = rbon1;   darkpix = rbon; }
               else { litpix = rboff1;  darkpix = rboff; }

  lit = 1;
  XCopyArea(theDisp, litpix, rb->win, theGC, 0, 0, rb_on_width, rb_on_height, 
	      rb->x, rb->y);
  XFlush(theDisp);
  Timer(75);          /* give chance for 'turn on' to become visible */

  while (XQueryPointer(theDisp,rb->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
    if (!(mask & Button1Mask)) break;    /* button released */

    if (!lit && PTINRECT(x, y, rb->x, rb->y, rb_on_width, rb_on_height)) {
      lit=1;
      XCopyArea(theDisp, litpix, rb->win, theGC, 0,0,rb_on_width,rb_on_height, 
	      rb->x, rb->y);
      XFlush(theDisp);
    }
    
    if (lit && !PTINRECT(x, y, rb->x, rb->y, rb_on_width, rb_on_height)) {
      lit=0;
      XCopyArea(theDisp, darkpix,rb->win,theGC, 0,0,rb_on_width,rb_on_height, 
	      rb->x, rb->y);
      XFlush(theDisp);
    }
  }

  if (lit) {
    XCopyArea(theDisp, darkpix, rb->win, theGC, 0, 0, 
	      rb_on_width, rb_on_height, rb->x, rb->y);
    RBSelect(rblist, n);
  }

  XFlush(theDisp);
}
\BARFOO\
else
  echo "will not over write ./xvbutt.c"
fi
if `test ! -s ./xvctrl.c`
then
echo "writting ./xvctrl.c"
cat > ./xvctrl.c << '\BARFOO\'
/* 
 * xvctrl.c - Control box handling functions
 *
 * callable functions:
 *
 *   CreateCtrl(geom)       -  creates the ctrlW window.  Doesn't map it.
 *   CtrlBox(vis)           -  random processing based on value of 'vis'
 *                             maps/unmaps window, etc.
 *   RedrawCtrl(x,y,w,h)    -  called by 'expose' events
 *   ClickCtrl(x,y)
 *   DrawCtrlStr()          -  called to redraw 'ISTR_INFO' string in ctrlW
 *   ScrollToCurrent()      -  called when 'curname' is changed 
 *
 *   LSCreate()             -  creates a listbox
 *   LSRedraw()             -  redraws 'namelist' box
 *   LSClick()              -  operates list box
 *   LSNewData()            -  called when strings or number of them change
 *
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */


#include "xv.h"
#include "bitmaps.h"

#define DBLCLKTIME 500             /* double-click speed in milliseconds */

#define INACTIVE(lptr, item) ((lptr)->filetypes && (lptr)->dirsonly && \
			      (item) >= 0 && (item) < (lptr)->nstr && \
			      (lptr)->str[(item)][0] != C_DIR && \
			      (lptr)->str[(item)][0] != C_LNK)

#define NLINES 9                   /* # of lines in list control (keep odd) */
#define LISTW   330

#define BUTTW   60
#define BUTTH   19

static int    listh;               /* height of list/scrl controls */
static int    ptop;                /* y-coord of top of button area in ctrlW */

static Pixmap fifoPix, chrPix, dirPix, blkPix, lnkPix, sockPix, regPix;

#ifdef __STDC__
static void drawSel(LIST *, int);
static void RedrawNList(void);
#else
static void drawSel(), RedrawNList();
#endif


/***************************************************/
void CreateCtrl(geom)
char *geom;
{
  int i,b2wide;

  ctrlW = CreateWindow("xv controls", geom, CTRLWIDE,CTRLHIGH,infofg,infobg);
  if (!ctrlW) FatalError("can't create controls window!");

  grayTile = XCreatePixmapFromBitmapData(theDisp, ctrlW, gray25_bits,
	     gray25_width, gray25_height, infofg, infobg, dispDEEP);

  grayStip = XCreatePixmapFromBitmapData(theDisp, ctrlW, gray50_bits,
	     gray50_width, gray50_height, 1, 0, 1);
  
  fifoPix  = XCreatePixmapFromBitmapData(theDisp, ctrlW, i_fifo_bits,
	     i_fifo_width, i_fifo_height, 1, 0, 1);
  
  chrPix  = XCreatePixmapFromBitmapData(theDisp, ctrlW, i_chr_bits,
	     i_chr_width, i_chr_height, 1,0,1);
  
  dirPix  = XCreatePixmapFromBitmapData(theDisp, ctrlW, i_dir_bits,
	     i_dir_width, i_dir_height, 1,0,1);
  
  blkPix  = XCreatePixmapFromBitmapData(theDisp, ctrlW, i_blk_bits,
	     i_blk_width, i_blk_height, 1,0,1);
  
  lnkPix  = XCreatePixmapFromBitmapData(theDisp, ctrlW, i_lnk_bits,
	     i_lnk_width, i_lnk_height, 1,0,1);
  
  sockPix  = XCreatePixmapFromBitmapData(theDisp, ctrlW, i_sock_bits,
	     i_sock_width, i_sock_height, 1,0,1);
  
  regPix  = XCreatePixmapFromBitmapData(theDisp, ctrlW, i_reg_bits,
	     i_reg_width, i_reg_height, 1,0,1);
  

  XSetWindowBackgroundPixmap(theDisp, ctrlW, grayTile);

  /* create doo-wahs */
  listh = LINEHIGH * NLINES;

  LSCreate(&nList, ctrlW, 10, 10+CHIGH+3, LISTW, listh, NLINES, dispnames, 
	   numnames, infofg, infobg, RedrawNList, 0, 0);

  ptop = CTRLHIGH - (3*BUTTH + 4*8);

  i = listh-BUTTH;

  BTCreate(&but[BNEXT], ctrlW, 368, nList.y+(i*0)/4, 60, 
	   BUTTH, "Next",     infofg, infobg);
  BTCreate(&but[BPREV], ctrlW, 368, nList.y+(i*1)/4, 60, 
	   BUTTH, "Previous", infofg, infobg);
  BTCreate(&but[BINFO], ctrlW, 368, nList.y+(i*2)/4, 60, 
	   BUTTH, "Info", infofg, infobg);
  BTCreate(&but[BSAVE], ctrlW, 368, nList.y+(i*3)/4, 60, 
	   BUTTH, "Save", infofg, infobg);
  BTCreate(&but[BQUIT], ctrlW, 368, nList.y+(i*4)/4, 60, 
	   BUTTH, "Quit", infofg, infobg);

  BTCreate(&but[BCROP], ctrlW, 10, ptop+8, 
	   BUTTW, BUTTH, "Crop", infofg, infobg);
  BTCreate(&but[BUNCROP], ctrlW, 10, ptop + BUTTH + 2*8, 
	   BUTTW, BUTTH, "UnCrop", infofg, infobg);

  BTCreate(&but[BMAX], ctrlW, 10+(CTRLWIDE-20-BUTTW)/5, ptop+8, 
	   BUTTW, BUTTH, "Max Size", infofg, infobg);
  BTCreate(&but[BNORM], ctrlW, 10+(CTRLWIDE-20-BUTTW)/5, ptop + BUTTH + 2*8, 
	   BUTTW, BUTTH, "Normal", infofg, infobg);

  BTCreate(&but[BUP2], ctrlW, 10+(2*(CTRLWIDE-20-BUTTW))/5, ptop+8, 
	   BUTTW, BUTTH, "Dbl Size", infofg, infobg);
  BTCreate(&but[BDN2], ctrlW, 10+(2*(CTRLWIDE-20-BUTTW))/5, ptop+BUTTH+2*8, 
	   BUTTW, BUTTH, "Half Size", infofg, infobg);

  BTCreate(&but[BUP10], ctrlW, 10+(3*(CTRLWIDE-20-BUTTW))/5, ptop+8, 
	   BUTTW, BUTTH, "+10%", infofg, infobg);
  BTCreate(&but[BDN10], ctrlW, 10+(3*(CTRLWIDE-20-BUTTW))/5, ptop+BUTTH+2*8, 
	   BUTTW, BUTTH, "-10%", infofg, infobg);

  BTCreate(&but[B4BY3], ctrlW, 10+(4*(CTRLWIDE-20-BUTTW))/5, ptop+8, 
	   BUTTW, BUTTH, "4x3", infofg, infobg);
  BTCreate(&but[BASPECT], ctrlW, 10+(4*(CTRLWIDE-20-BUTTW))/5, ptop+BUTTH+2*8, 
	   BUTTW, BUTTH, "Aspect", infofg, infobg);

  BTCreate(&but[BROTL],  ctrlW, 10+(5*(CTRLWIDE-20-BUTTW))/5, ptop+8,
	   BUTTW, BUTTH, "Turn L", infofg, infobg);
  BTCreate(&but[BROTR],  ctrlW, 10+(5*(CTRLWIDE-20-BUTTW))/5, ptop+BUTTH+2*8,
	   BUTTW, BUTTH, "Turn R", infofg, infobg);

  b2wide = (CTRLWIDE - 20 - 6*BUTTW)/5 + 2*BUTTW;
  BTCreate(&but[BACROP], ctrlW, 10 + (0*(CTRLWIDE-20-b2wide))/2, 
	   ptop + 2*BUTTH + 3*8, b2wide, BUTTH, "AutoCrop", infofg, infobg);
  BTCreate(&but[BMAXPECT],   ctrlW, 10 + (1*(CTRLWIDE-20-b2wide))/2, 
	   ptop + 2*BUTTH + 3*8, b2wide, BUTTH, "Maxpect", infofg, infobg);
  BTCreate(&but[BGAMMA],    ctrlW, 10 + (2*(CTRLWIDE-20-b2wide))/2, 
	   ptop + 2*BUTTH + 3*8, b2wide, BUTTH, "Gamma", infofg, infobg);

  XMapSubwindows(theDisp, ctrlW);
}
  

/***************************************************/
void CtrlBox(vis)
int vis;
{
  if (vis) XMapRaised(theDisp, ctrlW);
  else     XUnmapWindow(theDisp, ctrlW);

  ctrlUp = vis;
}


/***************************************************/
void RedrawCtrl(x,y,w,h)
int x,y,w,h;
{
  char foo[40];
  int i;
  XRectangle xr;

  xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
  XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);

  XSetForeground(theDisp, theGC, infofg);
  XSetBackground(theDisp, theGC, infobg);

  XDrawLine(theDisp, ctrlW, theGC, 0, ptop, CTRLWIDE, ptop);

  if (numnames>1) sprintf(foo,"%d files",numnames);
  else strcpy(foo,"1 file");
    
  XSetForeground(theDisp, theGC, infobg);
  XFillRectangle(theDisp,ctrlW, theGC, 10+1,5+1,StringWidth(foo)+4,CHIGH+2);
  XSetForeground(theDisp,theGC,infofg);
  XDrawRectangle(theDisp,ctrlW, theGC, 10,5,StringWidth(foo)+5,CHIGH+3);
  XDrawString(theDisp, ctrlW, theGC, 10+3, 5+ASCENT+2,
	      foo, strlen(foo));
 
  for (i=0; i<NBUTTS; i++)
    BTRedraw(&but[i]);

  DrawCtrlStr();

  XSetClipMask(theDisp, theGC, None);
}


/***************************************************/
void DrawCtrlStr()
{
  int   y;
  char *st;

  y = ptop - (CHIGH + 2);
  st = GetISTR(ISTR_INFO);

  XSetForeground(theDisp, theGC, infobg);
  XFillRectangle(theDisp, ctrlW, theGC, 0, y-1, CTRLWIDE, CHIGH+3);

  XSetForeground(theDisp, theGC, infofg);
  XDrawLine(theDisp, ctrlW, theGC, 0, y-2, CTRLWIDE, y-2);

  XDrawString(theDisp, ctrlW, theGC, 10, y+ASCENT, st, strlen(st));
}


/***************************************************/
int ClickCtrl(x,y)
int x,y;
{
  BUTT *bp;
  int   i;

  for (i=0; i<NBUTTS; i++) {
    bp = &but[i];
    if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
  }

  if (i<NBUTTS) {                   /* found one */
    if (BTTrack(bp)) return (i);    /* and it was clicked */
  }

  return -1;
}



/***************************************************/
void ScrollToCurrent()
{
  /* called when 'curname' is changed by anything (next/prev buttons,
     wait timeout, whatever.  IF curname is already visible, just redraws
     list to reflect changed selection.  If not, trys to adjust 'liststart' 
     so that curname will appear in the center of the list window */

  int halfway;

  nList.selected = curname;
/*  if (nList.selected >= nList.scrl.val && 
      nList.selected <  nList.scrl.val + nList.nlines) LSRedraw(&nList); */

  if (nList.selected > nList.scrl.val && 
      nList.selected <  nList.scrl.val + nList.nlines-1) LSRedraw(&nList);
  else {
    halfway = (nList.nlines)/2;   /* offset to the halfway pt. of the list */
    SCSetVal(&nList.scrl, nList.selected - halfway);
  }
}


/***************************************************/
static void RedrawNList()
{
  LSRedraw(&nList);
}




/***************** LIST STUFF *********************/

/***************************************************/
void LSCreate(lp, win, x, y, w, h, nlines, strlist, nstr, fg, bg, fptr, 
	      typ, donly)
LIST         *lp;
Window        win;
int           x,y,w,h,nlines,nstr,typ,donly;
unsigned long fg, bg;
char        **strlist;    /* a pointer to a list of strings */
void        (*fptr)();
{
  lp->win = XCreateSimpleWindow(theDisp,win,x,y,w,h,1,infofg,infobg);
  if (!lp->win) FatalError("can't create list window!");

  lp->x = x;    lp->y = y;   
  lp->w = w;    lp->h = h;
  lp->fg = fg;  lp->bg = bg;
  lp->str      = strlist;
  lp->nstr     = nstr;
  lp->selected = 0;
  lp->nlines   = nlines;
  lp->filetypes= typ;
  lp->dirsonly = donly;

  XSelectInput(theDisp, lp->win, ExposureMask | ButtonPressMask);

  SCCreate(&lp->scrl, win, x+w, y, 1, h, 0, nstr-nlines, curname, nlines-1,
	   fg, bg, fptr);
}



/***************************************************/
void LSNewData(lp, strlist, nstr)
LIST         *lp;
char        **strlist;
int           nstr;
{
  lp->str = strlist;
  lp->nstr = nstr;
  lp->selected = 0;
  SCSetRange(&lp->scrl, 0, nstr - lp->nlines, 0, lp->nlines-1);
}


/***************************************************/
static void drawSel(lp,j)
LIST *lp;
int j;
{
  int i, inactive;
  unsigned long fg, bg;

  inactive = INACTIVE(lp,j);

  i = j - lp->scrl.val;
  if (i<0 || i>=lp->nlines) return;  /* off screen */

  if (j == lp->selected && !inactive && j<lp->nstr) 
       { fg = lp->bg;  bg = lp->fg; }  /* invert */
  else { fg = lp->fg;  bg = lp->bg; }

  XSetForeground(theDisp, theGC, bg);
  XFillRectangle(theDisp, lp->win, theGC, 0,i*LINEHIGH, lp->w, LINEHIGH);

  if (j>=0 && j<lp->nstr) {   /* only draw string if valid */
    /* make non-dirs inactive, if dirsonly and filetypes */
    XSetForeground(theDisp, theGC, fg);
    XSetBackground(theDisp, theGC, bg);

    if (!lp->filetypes) 
      XDrawString(theDisp, lp->win, theGC, 3, i*LINEHIGH + ASCENT + 1, 
		  lp->str[j], strlen(lp->str[j]));
    else {
      int ypos = i*LINEHIGH + (LINEHIGH - i_fifo_height)/2;

      if (lp->str[j][0] == C_FIFO) 
	XCopyPlane(theDisp, fifoPix, lp->win, theGC, 0, 0,
		   i_fifo_width, i_fifo_height, 3, ypos, 1L);

      else if (lp->str[j][0] == C_CHR) 
	XCopyPlane(theDisp, chrPix, lp->win, theGC, 0, 0,
		   i_chr_width, i_chr_height, 3, ypos, 1L);

      else if (lp->str[j][0] == C_DIR) 
	XCopyPlane(theDisp, dirPix, lp->win, theGC, 0, 0,
		   i_dir_width, i_dir_height, 3, ypos, 1L);

      else if (lp->str[j][0] == C_BLK) 
	XCopyPlane(theDisp, blkPix, lp->win, theGC, 0, 0,
		   i_blk_width, i_blk_height, 3, ypos, 1L);

      else if (lp->str[j][0] == C_LNK) 
	XCopyPlane(theDisp, lnkPix, lp->win, theGC, 0, 0,
		   i_lnk_width, i_lnk_height, 3, ypos, 1L);

      else if (lp->str[j][0] == C_SOCK) 
	XCopyPlane(theDisp, sockPix, lp->win, theGC, 0, 0,
		   i_sock_width, i_sock_height, 3, ypos, 1L);

      else  /* lp->str[j][0] == C_REG */
	XCopyPlane(theDisp, regPix, lp->win, theGC, 0, 0,
		   i_reg_width, i_reg_height, 3, ypos, 1L);


      XDrawString(theDisp, lp->win, theGC, 3 + i_fifo_width + 3, 
		  i*LINEHIGH + ASCENT + 1, 
		  lp->str[j]+1, strlen(lp->str[j]+1));

#ifdef STIPPLE
      if (inactive) { 
	/* stipple the icon by drawing 'bg' where there's 1's in the stipple */
	XSetFillStyle(theDisp, theGC, FillStippled);
	XSetStipple(theDisp, theGC, grayStip);
	XSetForeground(theDisp, theGC, bg);
	XSetBackground(theDisp, theGC, fg);
	XFillRectangle(theDisp,lp->win,theGC,3,i*LINEHIGH,lp->w,LINEHIGH);
	XSetForeground(theDisp, theGC, fg);
	XSetFillStyle(theDisp, theGC, FillSolid);
      }
#endif

    }
  }
}


/***************************************************/
void LSRedraw(lp)
LIST *lp;
{
  int  i;

  for (i = lp->scrl.val; i < lp->scrl.val + lp->nlines; i++) 
    drawSel(lp,i);
}


/***************************************************/
int LSClick(lp,ev)
LIST *lp;
XButtonEvent *ev;
{
  /* returns '-1' normally.  returns 0 -> numnames-1 for a goto */

  Window       rW, cW;
  int          rx, ry, x, y, sel, oldsel;
  unsigned int mask;
  static Time  lasttime=0;
  static int   lastsel = -1;

  x = ev->x;  y = ev->y;
  sel = lp->scrl.val + y/LINEHIGH;
  if (sel >= lp->nstr) sel = lp->selected;

  /* see if it's a double click */
  if (ev->time - lasttime < DBLCLKTIME && sel==lastsel 
      && (lp->scrl.val + y/LINEHIGH) < lp->nstr
      && !INACTIVE(lp,sel)) {
    return (sel);
  }

  lasttime = ev->time;  lastsel = sel;

  /* if not clicked on selected, turn off selected and select new one */
  if (sel != lp->selected) {
    oldsel = lp->selected;
    lp->selected = sel;
    drawSel(lp,sel);  drawSel(lp,oldsel);
    XFlush(theDisp);
  }

  while (XQueryPointer(theDisp,lp->win,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
    if (!(mask & Button1Mask)) break;    /* button released */

    if (y<0) { /* scroll up in list */ 
      if (lp->scrl.val > lp->scrl.min) {
	lp->selected = lp->scrl.val - 1;
	SCSetVal(&lp->scrl, lp->scrl.val - 1);
	Timer(100);
      }
    }

    else if (y > lp->h) { /* scroll down in list */
      if (lp->scrl.val < lp->scrl.max) {
	lp->selected = lp->scrl.val + lp->nlines;
	if (lp->selected >= lp->nstr) lp->selected = lp->nstr - 1;
	SCSetVal(&lp->scrl, lp->scrl.val + 1);
	Timer(100);
      }
    }

    else {
      sel = lp->scrl.val + y/LINEHIGH;
      if (sel >= lp->nstr) sel = lp->nstr - 1;

      if (sel != lp->selected && sel >= lp->scrl.val &&
	  sel < lp->scrl.val + lp->nlines) {  
	/* dragged to another on current page */
	oldsel = lp->selected;
	lp->selected = sel;
	drawSel(lp, sel);  drawSel(lp, oldsel);
	XFlush(theDisp);
      }
    }
  }

  return(-1);
}



\BARFOO\
else
  echo "will not over write ./xvctrl.c"
fi
if `test ! -s ./xvdir.c`
then
echo "writting ./xvdir.c"
cat > ./xvdir.c << '\BARFOO\'
/* 
 * xvdir.c - Directory changin', file i/o dialog box
 *
 * callable functions:
 *
 *   CreateDirW(geom,bwidth)-  creates the dirW window.  Doesn't map it.
 *   DirBox(vis)            -  random processing based on value of 'vis'
 *                             maps/unmaps window, etc.
 *   RedrawDirW(x,y,w,h)    -  called by 'expose' events
 *   ClickDirW()            -  handles mouse clicks in DirW
 *   LoadCurrentDirectory() -  loads up current dir information for dirW
 *   DoSave()               -  calls appropriate save routines
 *   SetDirFName()          -  sets the 'save-as' filename 
 */

/*
 * Copyright 1989, 1990 by the University of Pennsylvania
 *
 * Permission to use, copy, and distribute for non-commercial purposes,
 * is hereby granted without fee, providing that the above copyright
 * notice appear in all copies and that both the copyright notice and this
 * permission notice appear in supporting documentation.
 *
 * The software may be modified for your own purposes, but modified versions
 * may not be distributed.
 *
 * This software is provided "as is" without any express or implied warranty.
 */


#define NEEDSDIR
#include "xv.h"

#define NLINES 9                   /* # of lines in list control (keep odd) */
#define LISTW  200

#define BUTTW   60
#define BUTTH   19
#define DDWIDE  LISTW-80+15

#define MAXDEEP 30    /* maximum number of directories in cwd path */
#define MAXFNLEN 40   /* max length of filename being entered */

#define DEFFILENAME ""   /* default filename filled in when program starts */

#ifdef __STDC__
static void RedrawDList(void);
static int  dnamcmp(char **, char **);
#else
static void RedrawDList();
static int  dnamcmp();
#endif

static int    listh;
static char  *dirnames[MAXNAMES];
static int    numdirnames = 0, ndirs = 0;
static char   path[MAXPATHLEN+1];
static char  *dirs[MAXDEEP];            /* list of directory names */
static char  *lastdir;                  /* name of the directory we're in */
static char   filename[MAXFNLEN];       /* filename being entered */
static RBUTT *formatRB, *colorRB, *sizeRB;


/***************************************************/
void CreateDirW(geom)
char *geom;
{
  int y;

  listh = LINEHIGH * NLINES;

  dirW = CreateWindow("xv save dialog",geom,DIRWIDE, DIRHIGH, infofg, infobg);
  if (!dirW) FatalError("couldn't create 'save' window!");

  /* create doo-wah's */
  ddirW = XCreateSimpleWindow(theDisp, dirW, 40, 5, DDWIDE, LINEHIGH,
			      2, infofg, infobg);
  if (!ddirW) FatalError("can't create path window");
  XSelectInput(theDisp, ddirW, ExposureMask | ButtonPressMask);

  dnamW = XCreateSimpleWindow(theDisp, dirW, 80, listh+75-ASCENT-4, 
			      200, LINEHIGH+4, 1, infofg, infobg);
  if (!dnamW) FatalError("can't create name window");
  XSelectInput(theDisp, dnamW, ExposureMask);


  LSCreate(&dList, dirW, 10, 14+LINEHIGH, LISTW, listh, NLINES,
	   dirnames, numdirnames,
	   infofg, infobg, RedrawDList, 1, 0);

  BTCreate(&dbut[S_BOPEN], dirW, 233, dList.y-9+listh/5, 60, BUTTH, 
	   "Open", infofg, infobg);
  BTCreate(&dbut[S_BSAVE], dirW, 233, dList.y-9+(listh*2)/5, 60, BUTTH, 
	   "Save", infofg, infobg);
  BTCreate(&dbut[S_BCANC], dirW, 233, dList.y-9+(listh*3)/5, 60, BUTTH, 
	   "Cancel", infofg, infobg);
  BTCreate(&dbut[S_BQUIT], dirW, 233, dList.y-9+(listh*4)/5, 60, BUTTH, 
	   "Quit", infofg, infobg);

  y = listh + 110;
  formatRB = RBCreate(NULL, dirW, 26, y, "GIF", infofg, infobg);
  RBCreate(formatRB, dirW, 26, y+18, "PM", infofg, infobg);
  RBCreate(formatRB, dirW, 26, y+36, "PBM (raw)", infofg, infobg);
  RBCreate(formatRB, dirW, 26, y+54, "PBM (ascii)", infofg, infobg);
  RBCreate(formatRB, dirW, 26, y+72, "X11 Bitmap", infofg, infobg);

  colorRB = RBCreate(NULL, dirW, DIRWIDE/2, y, "Full Color", infofg, infobg);
  RBCreate(colorRB, dirW, DIRWIDE/2, y+18, "Greyscale", infofg, infobg);
  RBCreate(colorRB, dirW, DIRWIDE/2, y+36, "B/W Dithered", infofg, infobg);

  y = y + 115;
  sizeRB = RBCreate(NULL, dirW, 26, y, "Normal Size", infofg, infobg);
  RBCreate(sizeRB, dirW, 26, y+18, "At Current Expansion", infofg, infobg);

  SetDirFName(DEFFILENAME);

  LoadCurrentDirectory();

  XMapSubwindows(theDisp, dirW);
}
  

/***************************************************/
void DirBox(vis)
int vis;
{
  if (vis) XMapRaised(theDisp, dirW);
  else     XUnmapWindow(theDisp, dirW);

  BTSetActive(&but[BSAVE], !vis);

  dirUp = vis;
}


/***************************************************/
void RedrawDirW(x,y,w,h)
int x,y,w,h;
{
  int  i,ypos;
  char foo[30];
  XRectangle xr;

  xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
  XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);

  if (dList.nstr==1) strcpy(foo,"1 file");
                else sprintf(foo,"%d files",dList.nstr);

  ypos = dList.y + dList.h + 5 + ASCENT;
  XSetForeground(theDisp, theGC, infobg);
  XFillRectangle(theDisp, dirW, theGC, 10, ypos-ASCENT, DIRWIDE, CHIGH);
  XSetForeground(theDisp, theGC, infofg);
  XDrawString(theDisp, dirW, theGC, 10, ypos, foo, strlen(foo));

  XDrawString(theDisp, dirW, theGC, 10, dList.h+75, "File name:",10);

  for (i=0; i<S_NBUTTS; i++) BTRedraw(&dbut[i]);

  RBRedraw(formatRB, -1);
  RBRedraw(colorRB, -1);
  RBRedraw(sizeRB, -1);

  ULineString(dirW, "Format", formatRB->x-16, formatRB->y-3-DESCENT);
  ULineString(dirW, "Colors", colorRB->x-16,  colorRB->y-3-DESCENT);
  ULineString(dirW, "Size",   sizeRB->x-16,   sizeRB->y-3-DESCENT);

  XSetClipMask(theDisp, theGC, None);
}


/***************************************************/
void RedrawDDirW()
{
  XSetForeground(theDisp, theGC, infofg);
  XSetBackground(theDisp, theGC, infobg);

  XClearWindow(theDisp, ddirW);
  XDrawString(theDisp, ddirW, theGC, 3, ASCENT + 1,
              lastdir, strlen(lastdir));
}


/***************************************************/
int ClickDirW(x,y)
int x,y;
{
  BUTT  *bp;
  int    bnum;


  /* check the RBUTTS first, since they don't DO anything */
  if ( (bnum=RBClick(formatRB, x,y)) >= 0) { 
    RBTrack(formatRB, bnum);
    if (RBWhich(formatRB)==4) {  /* turn off FULLCOLOR + GRAYSCALE */
      RBSetActive(colorRB,0,0);
      RBSetActive(colorRB,1,0);
      RBSelect(colorRB,2);
    }
    else {                       /* turn on FULLCOLOR + GRAYSCALE */
      RBSetActive(colorRB,0,1);
      RBSetActive(colorRB,1,1);
    }
    return -1;
  }

  if ( (bnum=RBClick(colorRB, x,y)) >= 0) 
    { RBTrack(colorRB, bnum);  return -1; }

  if ( (bnum=RBClick(sizeRB, x,y)) >= 0) 
    { RBTrack(sizeRB, bnum);  return -1; }

  for (bnum=0; bnum<S_NBUTTS; bnum++) {
    bp = &dbut[bnum];
    if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
  }

  if (bnum<S_NBUTTS) {   /* found one */
    if (BTTrack(bp)) return (bnum);
  }

  return -1;
}


/***************************************************/
void SelectDir(n)
int n;
{
  int pend;

  /* called when entry #n in the dir list was selected/double-clicked */

  if (dList.str[n][0] == C_DIR || 
      dList.str[n][0] == C_LNK) {  /* it's cool, it's (possibly) a directory */
    pend = strlen(path);
    strcat(path,dList.str[n]+1);   /* add to pathname */
    if (chdir(path)) {
      fprintf(stderr,"unable to cd to '%s'\n",path);
      path[pend] = '\0';           /* undo path modification */
    }
    else 
      LoadCurrentDirectory();
  }

  else {  /* not a directory */
    /* copy the clicked-on filename into the 'save-as' filename */
    SetDirFName(dList.str[n]+1);
  }
}


/***************************************************/
void TrackDDirW(x,y)
int x,y;
{
  Window        menuW, rW, cW;
  int           rx, ry, i,j, sel, lastsel;
  unsigned int  mask;

  XSetForeground(theDisp, theGC, infofg);
  XSetBackground(theDisp, theGC, infobg);

  menuW = XCreateSimpleWindow(theDisp, dirW, 40, 5, DDWIDE, ndirs*LINEHIGH,
			      2, infofg, infobg);
  if (!menuW) FatalError("can't create path window");

  XMapRaised(theDisp, menuW);

  for (i=ndirs-1, j=0; i>=0; i--,j++)
    XDrawString(theDisp, menuW, theGC, 3, j*LINEHIGH + ASCENT + 1,
		dirs[i], dirs[i+1]-dirs[i]);

  XFlush(theDisp);
  XSetFunction(theDisp, theGC, GXinvert);
  XSetPlaneMask(theDisp, theGC, infofg ^ infobg);
  lastsel = -1;  sel = 0;

  while (XQueryPointer(theDisp, menuW, &rW, &cW, &rx, &ry, &x, &y, &mask)) {
    if (!(mask & Button1Mask)) break;

    /* see if mouse has left window */

    sel = y / LINEHIGH;
    if (sel>=ndirs) sel = ndirs-1;
    if (sel<0) sel = 0;
    if (sel != lastsel) {
      XFillRectangle(theDisp,menuW,theGC,0,lastsel*LINEHIGH,DDWIDE,LINEHIGH);
      XFillRectangle(theDisp,menuW,theGC,0,sel*LINEHIGH,DDWIDE,LINEHIGH);
      lastsel = sel;
    }
  }

  XSetFunction(theDisp, theGC, GXcopy);
  XSetPlaneMask(theDisp, theGC, AllPlanes);
  XDestroyWindow(theDisp, menuW);

  if (sel!=0) { /* changed directories */
    /* end 'path' by changing trailing '/' (of dir name) to a '\0' */
    *(dirs[(ndirs-1)-sel + 1] - 1) = '\0';

    /* special case:  if cd to '/', fix path (it's currently "") */
    if (path[0] == '\0') strcpy(path,"/");

    if (chdir(path)) {
      fprintf(stderr,"unable to cd to '%s'\n",path);
    }
    else 
      LoadCurrentDirectory();   
  }
}


/***************************************************/
static void RedrawDList()
{
  LSRedraw(&dList);
}


/***************************************************/
void LoadCurrentDirectory()
{
  DIR           *dirp;
#ifdef DIRENT
  struct dirent *dp;
#else
  struct direct *dp;
#endif
  int            i, ftype;
  struct stat    st;
  char          *dbeg, *dend;

  /* get rid of previous file names */
  for (i=0; i<numdirnames; i++) free(dirnames[i]);

  numdirnames = 0;

#ifdef SYSV
  getcwd(path, sizeof(path));
#else
  getwd(path);
#endif
  if (path[strlen(path)-1] != '/')
    strcat(path,"/");   /* tack on a trailing '/' to make path consistent */

  /* path will be something like: "/u3/bradley/src/weiner/whatever/" */
  /* parse path into individual directory names */
  dbeg = dend = path;
  for (i=0; i<MAXDEEP && dend; i++) {
    dend = strchr(dbeg,'/');  /* find next '/' char */
    dirs[i] = dbeg;
    dbeg = dend+1;
  }
  ndirs = i-1;

  lastdir = dirs[ndirs-1];
  RedrawDDirW();

  dirp = opendir(".");
  if (!dirp) {
    fprintf(stderr,"unable to open current directory");
    return;
  }

  i=0;
  while ( (dp = readdir(dirp)) != NULL) {
    if (strcmp(dp->d_name, ".")==0 || strcmp(dp->d_name, "..")==0) {
      /* skip over '.' and '..' */
    }
    else {
#ifdef DIRENT
#ifdef i386
      /* Not 100% sure d_reclen is correct, but it works...  MWS 10/18/90 */
      dirnames[i] = (char *) malloc(dp->d_reclen + 2); /* filetype + '\0'*/
#else
      dirnames[i] = (char *) malloc(strlen(dp->d_name) + 3);
#endif
#else
      dirnames[i] = (char *) malloc(dp->d_namlen + 2); /* +2=filetype + '\0'*/
#endif
      if (!dirnames[i]) FatalError("malloc error while reading directory");
      strcpy(dirnames[i]+1, dp->d_name);

      /* figure out what type of file the beastie is */
      dirnames[i][0] = C_REG;   /* default to normal file, if lstat fails */

#if defined(i386) || defined (SYSV)
      if (stat(dirnames[i]+1, &st)==0) {
#else
      if (lstat(dirnames[i]+1, &st)==0) {
#endif
	ftype = st.st_mode & S_IFMT;   /* mask off uninteresting bits */
	if      (ftype == S_IFDIR)  dirnames[i][0] = C_DIR;
	else if (ftype == S_IFCHR)  dirnames[i][0] = C_CHR;
	else if (ftype == S_IFBLK)  dirnames[i][0] = C_BLK;

#ifdef S_IFIFO
	else if (ftype == S_IFIFO)  dirnames[i][0] = C_FIFO;
#endif

#ifdef S_IFLNK
	else if (ftype == S_IFLNK)  dirnames[i][0] = C_LNK;
#endif

#ifdef S_IFSOCK
        else if (ftype == S_IFSOCK) dirnames[i][0] = C_SOCK;
#endif
      }
      else {
	/* fprintf(stderr,"problems 'stat-ing' files\n");*/
	dirnames[i][0] = C_REG;
      }
      i++;
    }
  }

  closedir(dirp);

  numdirnames = i;

  qsort((char *) dirnames, numdirnames, sizeof(char *), dnamcmp);
  LSNewData(&dList, dirnames, numdirnames);
  DirOpenActive();
  RedrawDirW(0,0,DIRWIDE,DIRHIGH);
}


/***************************************************/
static int dnamcmp(s1,s2)
char **s1, **s2;
{
  /* sort so that directories are at beginning of list */

  /* if both dirs or both not dirs, sort on name */
  if ( (**s1 == C_DIR && **s2 == C_DIR) || (**s1 != C_DIR && **s2 != C_DIR))
    return (strcmp((*s1)+1, (*s2)+1));

  else if (**s1==C_DIR) return -1;  /* s1 is first */
  else return 1;                    /* s2 is first */
}





/***************************************************/
int DirKey(c)
int c;
{
  /* got keypress in dirW.  stick on end of filename */
  int len;

  len = strlen(filename);
  
  if (c>' ' && c<'\177') {              /* printable characters */
    if (c=='/') return(-1);             /* no directories in filename */
    if (len >= MAXFNLEN-1) return(-1);  /* max length of string */
    filename[len]=c;  filename[len+1]='\0';
  }

  else if (c=='\010' || c=='\177') {    /* BS or DEL */
    if (len==0) return(-1);             /* string already empty */
    filename[len-1]='\0';
  }

  else if (c=='\025' || c=='\013') {    /* ^U or ^K clear line */
    filename[0] = '\0';
  }

  else if (c=='\012' || c=='\015') {    /* CR or LF */
    FakeButtonPress(&dbut[S_BSAVE]);
  }

  else return(-1);                      /* unhandled character */

  SetDirFName(filename);
  return(0);
}


/***************************************************/
void RedrawDNamW()
{
  int width, len;

  len = strlen(filename);
  XSetForeground(theDisp, theGC, infofg);
  XDrawString(theDisp, dnamW, theGC, 3, ASCENT+3, filename, len);
  width = StringWidth(filename);
  XDrawLine(theDisp, dnamW, theGC, 3+width+1, 3, 3+width+1, 
	    3+CHIGH);
}


/***************************************************/
void DirOpenActive()
{
  if (dList.selected>=dList.nstr || dList.selected<0) 
    BTSetActive(&dbut[S_BOPEN],0);

  else if (dList.str[dList.selected][0] == C_DIR ||
      dList.str[dList.selected][0] == C_LNK) 
    BTSetActive(&dbut[S_BOPEN],1);

  else
    BTSetActive(&dbut[S_BOPEN],0);

  XFlush(theDisp);
}



/***************************************************/
int DoSave()
{
  FILE *fp;
  byte *thepic, *bwpic;
  int   w,h,rv,i;

  /* opens file, does appropriate color pre-processing, calls save routine
     based on chosen format.  Returns '0' if successful */

  WaitCursor();

  bwpic = NULL;

  if (RBWhich(sizeRB)==1) { thepic = epic;  w = eWIDE;  h = eHIGH; }
                     else { thepic = cpic;  w = cWIDE;  h = cHIGH; }

  if (RBWhich(colorRB)==2) {
    /* generate a FSDithered 1-byte per pixel image */
    bwpic = (byte *) malloc(w*h);
    if (!bwpic) FatalError("unable to malloc dithered picture (DoSave)");
    FSDither(thepic, w, h, bwpic);
    thepic = bwpic;
  }

  /* open file */
  fp = fopen(filename, "w");
  if (!fp) {
    SetISTR(ISTR_INFO,"Can't create '%s' -  %s",filename,sys_errlist[errno]);
    Warning();
    if (bwpic) free(bwpic);
    SetCursors(-1);
    return -1;
  }

  if ((mono || ncols==0) && RBWhich(colorRB)==0) {
    /* if we're saving color, but we're viewing B/W we have to NOT do
       the 'monofication' of the colormap ... */
    for (i=0; i<numcols; i++) {
      r[i] = rorg[i];  g[i] = gorg[i];  b[i] = borg[i];  /* original */
      
      if (revvideo) {
	r[i] = 255-r[i];  g[i] = 255-g[i];  b[i] = 255-b[i];
      }
   } 

    GammifyColors();
  }
      
  rv = 0;
  i = RBWhich(formatRB);
  switch (i) {
  case 0:  rv = WriteGIF(fp,thepic,w, h, r, g, b, numcols, RBWhich(colorRB));
           break;
  case 1:  rv = WritePM (fp,thepic,w, h, r, g, b, numcols, RBWhich(colorRB)); 
           break;
  case 2:  rv = WritePBM(fp,thepic,w, h, r, g, b, numcols, RBWhich(colorRB),1);
           break;
  case 3:  rv = WritePBM(fp,thepic,w, h, r, g, b, numcols, RBWhich(colorRB),0);
           break;
  case 4:  rv = WriteXBM(fp,thepic,w, h, filename);
           break;
  }

  fclose(fp);
  if (rv) unlink(filename);   /* couldn't properly write file:  delete it */

  if (!rv) {
    SetISTR(ISTR_INFO,"Successfully wrote '%s'",filename);
    LoadCurrentDirectory();   /* wrote file: rescan directory */
  }

  if (bwpic) free(bwpic);

  if ((mono || ncols==0) && RBWhich(colorRB)==0) {
    /* restore normal colormap */
    DoMonoAndRV();
    GammifyColors();
  }

  SetCursors(-1);

  return rv;
}



/***************************************************/
void SetDirFName(st)
char *st;
{
  strncpy(filename, st, MAXFNLEN-1);
  filename[MAXFNLEN-1] = '\0';  /* make sure it's terminated */
  XClearWindow(theDisp, dnamW);
  RedrawDNamW();
  BTSetActive(&dbut[S_BSAVE], strlen(filename)!=0);
}

\BARFOO\
else
  echo "will not over write ./xvdir.c"
fi
echo "Finished archive 7 of 10"
exit

dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.
--
dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.