REPOST: v09i079: XV -- successor to XGIF, Part04/08
John Bradley
bradley at grip.cis.upenn.edu
Thu Oct 11 07:14:53 AEST 1990
Submitted-by: bradley at grip.cis.upenn.edu (John Bradley)
Posting-number: Volume 9, Issue 79
Archive-name: xv/part04
-----------------------(cut here)---------------------------
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./xv24to8.c`
then
echo "writting ./xv24to8.c"
cat > ./xv24to8.c << '\BARFOO\'
/*
* xv24to8.c - contains the 24-to-8-bit Conv24to8 procedure
*
* The Conv24to8 procedure takes a pointer to a 24-bit image (loaded
* previously). The image will be a w * h * 3 byte array of
* bytes. The image will be arranged with 3 bytes per pixel (in order
* R, G, and B), pixel 0 at the top left corner. (As normal.)
* The procedure also takes a maximum number of colors to use (numcols)
*
* The Conv24to8 procedure will set up the following: it will allocate and
* create 'pic', a pWIDE*pHIGH 8-bit picture. it will set up pWIDE and pHIGH.
* it will load up the r[], g[], and b[] colormap arrays. it will NOT
* calculate numcols, since the cmap sort procedure has to be called anyway
*
* Conv24to8 returns '0' if successful, '1' if it failed (presumably on a
* malloc())
*
* contains:
* Cont24to8()
* InitFSDTables()
*/
/*
* 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"
#define MAX_CMAP_SIZE 256
#define COLOR_DEPTH 8
#define MAX_COLOR 256
#define B_DEPTH 5 /* # bits/pixel to use */
#define B_LEN (1<<B_DEPTH)
#define C_DEPTH 2
#define C_LEN (1<<C_DEPTH) /* # cells/color to use */
typedef struct colorbox {
struct colorbox *next, *prev;
int rmin,rmax, gmin,gmax, bmin,bmax;
int total;
} CBOX;
typedef struct {
int num_ents;
int entries[MAX_CMAP_SIZE][2];
} CCELL;
static byte *pic24;
static int num_colors, WIDE, HIGH;
static int histogram[B_LEN][B_LEN][B_LEN];
CBOX *freeboxes, *usedboxes;
CCELL **ColorCells;
static void get_histogram();
static CBOX *largest_box();
static void splitbox();
static void shrinkbox();
static void assign_color();
static CCELL *create_colorcell();
static void map_colortable();
static int quant_fsdither();
static int Quick24to8();
static int QuickCheck();
static byte tbl1[256], /* tables used in F-S Dithering */
tbl3[256], /* contain i/16, 3i/16, 5i/16, 7i/16, */
tbl5[256], /* (i=0-255) respectively */
tbl7[256];
/****************************/
int Conv24to8(p,w,h,nc)
/****************************/
byte *p;
int w,h,nc;
{
int i;
CBOX *box_list, *ptr;
/* copy arguments to local-global variables */
pic24 = p; pWIDE = WIDE = w; pHIGH = HIGH = h; num_colors = nc;
/* allocate pic immediately, so that if we can't allocate it, we don't
waste time running this algorithm */
pic = (byte *) malloc(WIDE * HIGH);
if (pic == NULL) {
fprintf(stderr,"%s: Conv24to8() - failed to allocate 'pic'\n",cmd);
return(1);
}
/* quick check: if we're going to display a greyscale or 1-bit image,
DON'T run this annoyingly time-consuming code. Just convert the 24-bit
color image to an 8-bit greyscale. This takes virtually no time, by
comparision, and it has the same effect. */
if (mono || nc==0) {
byte *pp, *p24;
for (i=0; i<256; i++) r[i]=g[i]=b[i]=i; /* greyscale colormap */
pp = pic; p24 = pic24;
for (i=WIDE*HIGH; i>0; i--, pp++, p24+=3)
*pp = (p24[0]*11 + p24[1]*16 + p24[2]*5) >> 5; /* pp=.33R+.5G+.17B */
return(0);
}
if (!noqcheck && QuickCheck(pic24,w,h,nc)) {
/* see if it's a <256 color RGB pic */
SetISTR(ISTR_INFO,"No color compression was necessary.\n");
return 0;
}
else if (!slow24) {
SetISTR(ISTR_INFO,"Doing quick 24-bit to 8-bit conversion.");
return(Quick24to8(pic24,w,h));
}
else
SetISTR(ISTR_INFO,"Doing full 24-bit to 8-bit conversion.");
/**** STEP 1: create empty boxes ****/
usedboxes = NULL;
box_list = freeboxes = (CBOX *) malloc(num_colors * sizeof(CBOX));
if (box_list == NULL) {
fprintf(stderr,"%s: Conv24to8() - failed to allocate 'freeboxes'\n",cmd);
return(1);
}
for (i=0; i<num_colors; i++) {
freeboxes[i].next = &freeboxes[i+1];
freeboxes[i].prev = &freeboxes[i-1];
}
freeboxes[0].prev = NULL;
freeboxes[num_colors-1].next = NULL;
/**** STEP 2: get histogram, initialize first box ****/
ptr = freeboxes;
freeboxes = ptr->next;
if (freeboxes) freeboxes->prev = NULL;
ptr->next = usedboxes;
usedboxes = ptr;
if (ptr->next) ptr->next->prev = ptr;
get_histogram(ptr);
/**** STEP 3: continually subdivide boxes until no more free boxes remain */
while (freeboxes) {
ptr = largest_box();
if (ptr) splitbox(ptr);
else break;
}
/**** STEP 4: assign colors to all boxes ****/
for (i=0, ptr=usedboxes; i<num_colors && ptr; i++, ptr=ptr->next) {
assign_color(ptr, &r[i], &g[i], &b[i]);
}
/* We're done with the boxes now */
num_colors = i;
free(box_list);
box_list = freeboxes = usedboxes = NULL;
/**** STEP 5: scan histogram and map all values to closest color */
/* 5a: create cell list as described in Heckbert[2] */
ColorCells = (CCELL **) calloc(C_LEN*C_LEN*C_LEN, sizeof(CCELL *));
/* 5b: create mapping from truncated pixel space to color table entries */
map_colortable();
/**** STEP 6: scan image, match input values to table entries */
i=quant_fsdither();
/* free everything that can be freed */
free(ColorCells);
return i;
}
/****************************/
static void get_histogram(box)
CBOX *box;
/****************************/
{
int i,j,r,g,b,*ptr;
byte *p;
box->rmin = box->gmin = box->bmin = 999;
box->rmax = box->gmax = box->bmax = -1;
box->total = WIDE * HIGH;
/* zero out histogram */
ptr = &histogram[0][0][0];
for (i=B_LEN*B_LEN*B_LEN; i>0; i-- ) *ptr++ = 0;
/* calculate histogram */
p = pic24;
for (i=0; i<HIGH; i++)
for (j=0; j<WIDE; j++) {
r = (*p++) >> (COLOR_DEPTH-B_DEPTH);
g = (*p++) >> (COLOR_DEPTH-B_DEPTH);
b = (*p++) >> (COLOR_DEPTH-B_DEPTH);
if (r < box->rmin) box->rmin = r;
if (r > box->rmax) box->rmax = r;
if (g < box->gmin) box->gmin = g;
if (g > box->gmax) box->gmax = g;
if (b < box->bmin) box->bmin = b;
if (b > box->bmax) box->bmax = b;
histogram[r][g][b]++;
}
}
/******************************/
static CBOX *largest_box()
/******************************/
{
CBOX *tmp, *ptr;
int size = -1;
tmp = usedboxes;
ptr = NULL;
while (tmp) {
if ( (tmp->rmax > tmp->rmin ||
tmp->gmax > tmp->gmin ||
tmp->bmax > tmp->bmin) && tmp->total > size ) {
ptr = tmp;
size = tmp->total;
}
tmp = tmp->next;
}
return(ptr);
}
/******************************/
static void splitbox(ptr)
CBOX *ptr;
/******************************/
{
int hist2[B_LEN], first, last, i, rdel, gdel, bdel;
CBOX *new;
int *iptr, *histp, ir, ig, ib;
int rmin,rmax,gmin,gmax,bmin,bmax;
enum {RED,GREEN,BLUE} which;
/*
* see which axis is the largest, do a histogram along that
* axis. Split at median point. Contract both new boxes to
* fit points and return
*/
first = last = 0; /* shut RT hcc compiler up */
rmin = ptr->rmin; rmax = ptr->rmax;
gmin = ptr->gmin; gmax = ptr->gmax;
bmin = ptr->bmin; bmax = ptr->bmax;
rdel = rmax - rmin;
gdel = gmax - gmin;
bdel = bmax - bmin;
if (rdel>=gdel && rdel>=bdel) which = RED;
else if (gdel>=bdel) which = GREEN;
else which = BLUE;
/* get histogram along longest axis */
switch (which) {
case RED:
histp = &hist2[rmin];
for (ir=rmin; ir<=rmax; ir++) {
*histp = 0;
for (ig=gmin; ig<=gmax; ig++) {
iptr = &histogram[ir][ig][bmin];
for (ib=bmin; ib<=bmax; ib++) {
*histp += *iptr;
++iptr;
}
}
++histp;
}
first = rmin; last = rmax;
break;
case GREEN:
histp = &hist2[gmin];
for (ig=gmin; ig<=gmax; ig++) {
*histp = 0;
for (ir=rmin; ir<=rmax; ir++) {
iptr = &histogram[ir][ig][bmin];
for (ib=bmin; ib<=bmax; ib++) {
*histp += *iptr;
++iptr;
}
}
++histp;
}
first = gmin; last = gmax;
break;
case BLUE:
histp = &hist2[bmin];
for (ib=bmin; ib<=bmax; ib++) {
*histp = 0;
for (ir=rmin; ir<=rmax; ir++) {
iptr = &histogram[ir][gmin][ib];
for (ig=gmin; ig<=gmax; ig++) {
*histp += *iptr;
iptr += B_LEN;
}
}
++histp;
}
first = bmin; last = bmax;
break;
}
/* find median point */
{
int sum, sum2;
histp = &hist2[first];
sum2 = ptr->total/2;
histp = &hist2[first];
sum = 0;
for (i=first; i<=last && (sum += *histp++)<sum2; i++);
if (i==first) i++;
}
/* Create new box, re-allocate points */
new = freeboxes;
freeboxes = new->next;
if (freeboxes) freeboxes->prev = NULL;
if (usedboxes) usedboxes->prev = new;
new->next = usedboxes;
usedboxes = new;
{
int sum1,sum2,j;
histp = &hist2[first];
sum1 = 0;
for (j = first; j < i; ++j) sum1 += *histp++;
sum2 = 0;
for (j = i; j <= last; ++j) sum2 += *histp++;
new->total = sum1;
ptr->total = sum2;
}
new->rmin = rmin; new->rmax = rmax;
new->gmin = gmin; new->gmax = gmax;
new->bmin = bmin; new->bmax = bmax;
switch (which) {
case RED: new->rmax = i-1; ptr->rmin = i; break;
case GREEN: new->gmax = i-1; ptr->gmin = i; break;
case BLUE: new->bmax = i-1; ptr->bmin = i; break;
}
shrinkbox(new);
shrinkbox(ptr);
}
/****************************/
static void shrinkbox(box)
CBOX *box;
/****************************/
{
int *histp,ir,ig,ib;
int rmin,rmax,gmin,gmax,bmin,bmax;
rmin = box->rmin; rmax = box->rmax;
gmin = box->gmin; gmax = box->gmax;
bmin = box->bmin; bmax = box->bmax;
if (rmax>rmin) {
for (ir=rmin; ir<=rmax; ir++)
for (ig=gmin; ig<=gmax; ig++) {
histp = &histogram[ir][ig][bmin];
for (ib=bmin; ib<=bmax; ib++)
if (*histp++ != 0) {
box->rmin = rmin = ir;
goto have_rmin;
}
}
have_rmin:
if (rmax>rmin)
for (ir=rmax; ir>=rmin; --ir)
for (ig=gmin; ig<=gmax; ig++) {
histp = &histogram[ir][ig][bmin];
for (ib=bmin; ib<=bmax; ib++)
if (*histp++ != 0) {
box->rmax = rmax = ir;
goto have_rmax;
}
}
}
have_rmax:
if (gmax>gmin) {
for (ig=gmin; ig<=gmax; ig++)
for (ir=rmin; ir<=rmax; ir++) {
histp = &histogram[ir][ig][bmin];
for (ib=bmin; ib<=bmax; ib++)
if (*histp++ != 0) {
box->gmin = gmin = ig;
goto have_gmin;
}
}
have_gmin:
if (gmax>gmin)
for (ig=gmax; ig>=gmin; --ig)
for (ir=rmin; ir<=rmax; ir++) {
histp = &histogram[ir][ig][bmin];
for (ib=bmin; ib<=bmax; ib++)
if (*histp++ != 0) {
box->gmax = gmax = ig;
goto have_gmax;
}
}
}
have_gmax:
if (bmax>bmin) {
for (ib=bmin; ib<=bmax; ib++)
for (ir=rmin; ir<=rmax; ir++) {
histp = &histogram[ir][gmin][ib];
for (ig=gmin; ig<=gmax; ig++) {
if (*histp != 0) {
box->bmin = bmin = ib;
goto have_bmin;
}
histp += B_LEN;
}
}
have_bmin:
if (bmax>bmin)
for (ib=bmax; ib>=bmin; --ib)
for (ir=rmin; ir<=rmax; ir++) {
histp = &histogram[ir][gmin][ib];
for (ig=gmin; ig<=gmax; ig++) {
if (*histp != 0) {
bmax = ib;
goto have_bmax;
}
histp += B_LEN;
}
}
}
have_bmax: return;
}
/*******************************/
static void assign_color(ptr,rp,gp,bp)
CBOX *ptr;
byte *rp,*gp,*bp;
/*******************************/
{
*rp = ((ptr->rmin + ptr->rmax) << (COLOR_DEPTH - B_DEPTH)) / 2;
*gp = ((ptr->gmin + ptr->gmax) << (COLOR_DEPTH - B_DEPTH)) / 2;
*bp = ((ptr->bmin + ptr->bmax) << (COLOR_DEPTH - B_DEPTH)) / 2;
}
/*******************************/
static CCELL *create_colorcell(r1,g1,b1)
int r1,g1,b1;
/*******************************/
{
register int i,tmp, dist;
register CCELL *ptr;
register byte *rp,*gp,*bp;
int ir,ig,ib, mindist;
ir = r1 >> (COLOR_DEPTH-C_DEPTH);
ig = g1 >> (COLOR_DEPTH-C_DEPTH);
ib = b1 >> (COLOR_DEPTH-C_DEPTH);
r1 &= ~1 << (COLOR_DEPTH-C_DEPTH);
g1 &= ~1 << (COLOR_DEPTH-C_DEPTH);
b1 &= ~1 << (COLOR_DEPTH-C_DEPTH);
ptr = (CCELL *) malloc(sizeof(CCELL));
*(ColorCells + ir*C_LEN*C_LEN + ig*C_LEN + ib) = ptr;
ptr->num_ents = 0;
/* step 1: find all colors inside this cell, while we're at
it, find distance of centermost point to furthest
corner */
mindist = 99999999;
rp=r; gp=g; bp=b;
for (i=0; i<num_colors; i++,rp++,gp++,bp++)
if( *rp>>(COLOR_DEPTH-C_DEPTH) == ir &&
*gp>>(COLOR_DEPTH-C_DEPTH) == ig &&
*bp>>(COLOR_DEPTH-C_DEPTH) == ib) {
ptr->entries[ptr->num_ents][0] = i;
ptr->entries[ptr->num_ents][1] = 0;
++ptr->num_ents;
tmp = *rp - r1;
if (tmp < (MAX_COLOR/C_LEN/2)) tmp = MAX_COLOR/C_LEN-1 - tmp;
dist = tmp*tmp;
tmp = *gp - g1;
if (tmp < (MAX_COLOR/C_LEN/2)) tmp = MAX_COLOR/C_LEN-1 - tmp;
dist += tmp*tmp;
tmp = *bp - b1;
if (tmp < (MAX_COLOR/C_LEN/2)) tmp = MAX_COLOR/C_LEN-1 - tmp;
dist += tmp*tmp;
if (dist < mindist) mindist = dist;
}
/* step 3: find all points within that distance to box */
rp=r; gp=g; bp=b;
for (i=0; i<num_colors; i++,rp++,gp++,bp++)
if (*rp >> (COLOR_DEPTH-C_DEPTH) != ir ||
*gp >> (COLOR_DEPTH-C_DEPTH) != ig ||
*bp >> (COLOR_DEPTH-C_DEPTH) != ib) {
dist = 0;
if ((tmp = r1 - *rp)>0 || (tmp = *rp - (r1 + MAX_COLOR/C_LEN-1)) > 0 )
dist += tmp*tmp;
if( (tmp = g1 - *gp)>0 || (tmp = *gp - (g1 + MAX_COLOR/C_LEN-1)) > 0 )
dist += tmp*tmp;
if( (tmp = b1 - *bp)>0 || (tmp = *bp - (b1 + MAX_COLOR/C_LEN-1)) > 0 )
dist += tmp*tmp;
if( dist < mindist ) {
ptr->entries[ptr->num_ents][0] = i;
ptr->entries[ptr->num_ents][1] = dist;
++ptr->num_ents;
}
}
/* sort color cells by distance, use cheap exchange sort */
{
int n, next_n;
n = ptr->num_ents - 1;
while (n>0) {
next_n = 0;
for (i=0; i<n; ++i) {
if (ptr->entries[i][1] > ptr->entries[i+1][1]) {
tmp = ptr->entries[i][0];
ptr->entries[i][0] = ptr->entries[i+1][0];
ptr->entries[i+1][0] = tmp;
tmp = ptr->entries[i][1];
ptr->entries[i][1] = ptr->entries[i+1][1];
ptr->entries[i+1][1] = tmp;
next_n = i;
}
}
n = next_n;
}
}
return (ptr);
}
/***************************/
static void map_colortable()
/***************************/
{
int ir,ig,ib, *histp;
CCELL *cell;
histp = &histogram[0][0][0];
for (ir=0; ir<B_LEN; ir++)
for (ig=0; ig<B_LEN; ig++)
for (ib=0; ib<B_LEN; ib++) {
if (*histp==0) *histp = -1;
else {
int i, j, tmp, d2, dist;
cell = *(ColorCells +
( ((ir>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2)
+ ((ig>>(B_DEPTH-C_DEPTH)) << C_DEPTH)
+ (ib>>(B_DEPTH-C_DEPTH)) ) );
if (cell==NULL)
cell = create_colorcell(ir<<(COLOR_DEPTH-B_DEPTH),
ig<<(COLOR_DEPTH-B_DEPTH),
ib<<(COLOR_DEPTH-B_DEPTH));
dist = 9999999;
for (i=0; i<cell->num_ents && dist>cell->entries[i][1]; i++) {
j = cell->entries[i][0];
d2 = r[j] - (ir << (COLOR_DEPTH-B_DEPTH));
d2 *= d2;
tmp = g[j] - (ig << (COLOR_DEPTH-B_DEPTH));
d2 += tmp*tmp;
tmp = b[j] - (ib << (COLOR_DEPTH-B_DEPTH));
d2 += tmp*tmp;
if( d2 < dist ) { dist = d2; *histp = j; }
}
}
histp++;
}
}
/*****************************/
static int quant_fsdither()
/*****************************/
{
register int *thisptr, *nextptr;
int *thisline, *nextline, *tmpptr;
int r1, g1, b1, r2, g2, b2;
int i, j, imax, jmax, oval;
byte *inptr, *outptr, *tmpbptr;
int lastline, lastpixel;
imax = HIGH - 1;
jmax = WIDE - 1;
thisline = (int *) malloc(WIDE * 3 * sizeof(int));
nextline = (int *) malloc(WIDE * 3 * sizeof(int));
if (thisline == NULL || nextline == NULL) {
fprintf(stderr,"%s: unable to allocate stuff for the 'dither' routine\n",
cmd);
return 1;
}
inptr = (byte *) pic24;
outptr = (byte *) pic;
/* get first line of picture */
for (j=WIDE * 3, tmpptr=nextline, tmpbptr=inptr; j; j--)
*tmpptr++ = (int) *tmpbptr++;
for (i=0; i<HIGH; i++) {
/* swap thisline and nextline */
tmpptr = thisline; thisline = nextline; nextline = tmpptr;
lastline = (i==imax);
/* read in next line */
for (j=WIDE * 3, tmpptr=nextline; j; j--)
*tmpptr++ = (int) *inptr++;
/* dither this line and put it into the output picture */
thisptr = thisline; nextptr = nextline;
for (j=0; j<WIDE; j++) {
lastpixel = (j==jmax);
r2 = *thisptr++; g2 = *thisptr++; b2 = *thisptr++;
if (r2<0) r2=0; else if (r2>=MAX_COLOR) r2=MAX_COLOR-1;
if (g2<0) g2=0; else if (g2>=MAX_COLOR) g2=MAX_COLOR-1;
if (b2<0) b2=0; else if (b2>=MAX_COLOR) b2=MAX_COLOR-1;
r1 = r2; g1 = g2; b1 = b2;
r2 >>= (COLOR_DEPTH-B_DEPTH);
g2 >>= (COLOR_DEPTH-B_DEPTH);
b2 >>= (COLOR_DEPTH-B_DEPTH);
if ( (oval=histogram[r2][g2][b2]) == -1) {
int ci, cj, dist, d2, tmp;
CCELL *cell;
cell = *( ColorCells +
( ((r2>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2)
+ ((g2>>(B_DEPTH-C_DEPTH)) << C_DEPTH )
+ (b2>>(B_DEPTH-C_DEPTH)) ) );
if (cell==NULL) cell = create_colorcell(r1,g1,b1);
dist = 9999999;
for (ci=0; ci<cell->num_ents && dist>cell->entries[ci][1]; ci++) {
cj = cell->entries[ci][0];
d2 = (r[cj] >> (COLOR_DEPTH-B_DEPTH)) - r2;
d2 *= d2;
tmp = (g[cj] >> (COLOR_DEPTH-B_DEPTH)) - g2;
d2 += tmp*tmp;
tmp = (b[cj] >> (COLOR_DEPTH-B_DEPTH)) - b2;
d2 += tmp*tmp;
if (d2<dist) { dist = d2; oval = cj; }
}
histogram[r2][g2][b2] = oval;
}
*outptr++ = oval;
r1 -= r[oval]; g1 -= g[oval]; b1 -= b[oval];
/* can't use tables because r1,g1,b1 go negative */
if (!lastpixel) {
thisptr[0] += (r1*7)/16;
thisptr[1] += (g1*7)/16;
thisptr[2] += (b1*7)/16;
}
if (!lastline) {
if (j) {
nextptr[-3] += (r1*3)/16;
nextptr[-2] += (g1*3)/16;
nextptr[-1] += (b1*3)/16;
}
nextptr[0] += (r1*5)/16;
nextptr[1] += (g1*5)/16;
nextptr[2] += (b1*5)/16;
if (!lastpixel) {
nextptr[3] += r1/16;
nextptr[4] += g1/16;
nextptr[5] += b1/16;
}
nextptr += 3;
}
}
}
free(thisline); free(nextline);
return 0;
}
/************************************/
static int Quick24to8(p24,w,h)
byte *p24;
int w,h;
{
/* floyd-steinberg dithering.
*
* ---- x 7/16
* 3/16 5/16 1/16
*
*/
/* called after 'pic' has been alloced, pWIDE,pHIGH set up, mono/1-bit
checked already */
byte *pp;
int r1, g1, b1;
int *thisline, *nextline, *thisptr, *nextptr, *tmpptr;
int i, j, rerr, gerr, berr, pwide3;
int imax, jmax;
pp = pic; pwide3 = w * 3; imax = h-1; jmax = w-1;
/* load up colormap, 3 bits R, 3 bits G, 2 bits B (RRRGGGBB) */
#ifdef OLDCOLORS
for (i=0; i<256; i++) {
r[i] = i & 0xe0;
g[i] = (i & 0x1c) << 3;
b[i] = (i & 0x03) << 6;
}
#else
for (i=0; i<256; i++) {
r[i] = ((i&0xe0) * 255) / 0xe0;
g[i] = ((i&0x1c) * 255) / 0x1c;
b[i] = ((i&0x03) * 255) / 0x03;
}
#endif
thisline = (int *) malloc(pwide3 * sizeof(int));
nextline = (int *) malloc(pwide3 * sizeof(int));
if (!thisline || !nextline) {
fprintf(stderr,"%s: unable to allocate memory in Quick24to8()\n", cmd);
return(1);
}
/* get first line of picture */
for (j=pwide3, tmpptr=nextline; j; j--) *tmpptr++ = (int) *p24++;
for (i=0; i<h; i++) {
tmpptr = thisline; thisline = nextline; nextline = tmpptr; /* swap */
if (i!=imax) /* get next line */
for (j=pwide3, tmpptr=nextline; j; j--)
*tmpptr++ = (int) *p24++;
for (j=0, thisptr=thisline, nextptr=nextline; j<w; j++,pp++) {
r1 = *thisptr++; g1 = *thisptr++; b1 = *thisptr++;
RANGE(r1,0,255); RANGE(g1,0,255); RANGE(b1,0,255);
rerr = r1 & 0x1f; gerr = g1 & 0x1f; berr = b1 & 0x3f;
*pp = (r1&0xe0) | ((g1>>3)&0x1c) | (b1>>6);
if (j!=jmax) { /* adjust RIGHT pixel */
thisptr[0] += tbl7[rerr];
thisptr[1] += tbl7[gerr];
thisptr[2] += tbl7[berr];
}
if (i!=imax) { /* do BOTTOM pixel */
nextptr[0] += tbl5[rerr];
nextptr[1] += tbl5[gerr];
nextptr[2] += tbl5[berr];
if (j>0) { /* do BOTTOM LEFT pixel */
nextptr[-3] += tbl3[rerr];
nextptr[-2] += tbl3[gerr];
nextptr[-1] += tbl3[berr];
}
if (j!=jmax) { /* do BOTTOM RIGHT pixel */
nextptr[3] += tbl1[rerr];
nextptr[4] += tbl1[gerr];
nextptr[5] += tbl1[berr];
}
nextptr += 3;
}
}
}
return 0;
}
/****************************/
void InitFSDTables()
/****************************/
{
int i;
for (i=0; i<256; i++) { /* initialize Floyd-Steinberg division tables */
tbl1[i] = i/16;
tbl3[i] = (3*i)/16;
tbl5[i] = (5*i)/16;
tbl7[i] = (7*i)/16;
}
}
/****************************/
static int QuickCheck(pic24,w,h,maxcol)
byte *pic24;
int w,h,maxcol;
{
/* scans picture until it finds more than 'maxcol' different colors. If it
finds more than 'maxcol' colors, it returns '0'. If it DOESN'T, it does
the 24-to-8 conversion by simply sticking the colors it found into
a colormap, and changing instances of a color in pic24 into colormap
indicies (in pic) */
unsigned long colors[256],col;
int i, nc, low, high, mid, k;
byte *p, *pix;
if (maxcol>256) maxcol = 256;
/* put the first color in the table by hand */
nc = 0;
for (i=w*h,p=pic24; i; i--) {
col = (*p++ << 16);
col += (*p++ << 8);
col += *p++;
/* binary search the 'colors' array to see if it's in there */
low = 0; high = nc-1;
while (low <= high) {
mid = (low+high)/2;
if (col < colors[mid]) high = mid - 1;
else if (col > colors[mid]) low = mid + 1;
else break;
}
if (high < low) { /* didn't find color in list, add it. */
/* WARNING: this is an overlapped memory copy. memcpy doesn't do
it correctly, hence 'bcopy', which claims to */
bcopy(&colors[low], &colors[low+1], (nc - low) * sizeof(unsigned long));
colors[low] = col;
nc++;
if (nc>maxcol) return 0;
}
}
/* run through the data a second time, this time mapping pixel values in
pic24 into colormap offsets into 'colors' */
for (i=w*h,p=pic24, pix=pic; i; i--,pix++) {
col = (*p++ << 16);
col += (*p++ << 8);
col += *p++;
/* binary search the 'colors' array. It *IS* in there */
low = 0; high = nc-1;
while (low <= high) {
mid = (low+high)/2;
if (col < colors[mid]) high = mid - 1;
else if (col > colors[mid]) low = mid + 1;
else break;
}
if (high < low) {
fprintf(stderr,"QuickCheck: impossible!\n");
exit(1);
}
*pix = mid;
}
/* and load up the 'desired colormap' */
for (i=0; i<nc; i++) {
r[i] = colors[i]>>16;
g[i] = (colors[i]>>8) & 0xff;
b[i] = colors[i] & 0xff;
}
return 1;
}
\BARFOO\
else
echo "will not over write ./xv24to8.c"
fi
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;
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 - (2*BUTTH + 3*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[BROTATE], ctrlW, 10+(5*(CTRLWIDE-20-BUTTW))/5, ptop+8,
BUTTW, BUTTH, "Rotate", infofg, infobg);
BTCreate(&but[BGAMMA], ctrlW, 10+(5*(CTRLWIDE-20-BUTTW))/5, ptop+BUTTH+2*8,
BUTTW, 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 STIPPLE
}
}
}
/***************************************************/
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
echo "Finished archive 4 of 8"
exit
dan
----------------------------------------------------
O'Reilly && Associates argv at sun.com / argv at ora.com
Opinions expressed reflect those of the author only.
More information about the Comp.sources.x
mailing list