dslinux/user/pixil/libs/flek/src FDate.cxx FFile.cxx FImage.cxx FJPEG.cxx FPNM.cxx FSGI.cxx FSocket.cxx FSocket_Posix.H FSocket_Posix.cxx FVector.cxx Fl_App_Window.cxx Fl_Better_Window.cxx Fl_Calendar.cxx Fl_Dockable_Window.cxx Fl_Stock.cxx Fl_Time.cxx Fl_Toggle_Node.cxx Fl_Toggle_Node_Base.cxx Fl_Toggle_Tree.cxx Fl_Toggle_Tree_Base.cxx Flv_CStyle.cxx Flv_List.cxx Flv_Style.cxx Flv_Table.cxx Flve_Check_Button.cxx Flve_Combo.cxx Flve_Input.cxx Makefile makedepend

amadeus dslinux_amadeus at user.in-berlin.de
Tue Oct 3 13:24:53 CEST 2006


Update of /cvsroot/dslinux/dslinux/user/pixil/libs/flek/src
In directory antilope:/tmp/cvs-serv11916/libs/flek/src

Added Files:
	FDate.cxx FFile.cxx FImage.cxx FJPEG.cxx FPNM.cxx FSGI.cxx 
	FSocket.cxx FSocket_Posix.H FSocket_Posix.cxx FVector.cxx 
	Fl_App_Window.cxx Fl_Better_Window.cxx Fl_Calendar.cxx 
	Fl_Dockable_Window.cxx Fl_Stock.cxx Fl_Time.cxx 
	Fl_Toggle_Node.cxx Fl_Toggle_Node_Base.cxx Fl_Toggle_Tree.cxx 
	Fl_Toggle_Tree_Base.cxx Flv_CStyle.cxx Flv_List.cxx 
	Flv_Style.cxx Flv_Table.cxx Flve_Check_Button.cxx 
	Flve_Combo.cxx Flve_Input.cxx Makefile makedepend 
Log Message:
adding pristine copy of pixil to HEAD so I can branch from it

--- NEW FILE: Flv_Table.cxx ---
//      ======================================================================
//      File:    Flv_Table.cxx - Flv_Table implementation
//      Program: Flv_Table - FLTK Table Widget
//      Version: 0.1.0
//      Started: 11/21/99
//
//      Copyright (C) 1999 Laurence Charlton
//
//      Description:
//      Flv_Table implements a table/grid.  No data is stored
//      in the widget.  Supports headers/footers for rows and columns,
//      natively supports a single row height and column width per table.
//      Row and column grids can be turned on and off.  Supports no scroll
//      bars as well as horizontal/vertical automatic or always on scroll bars.
//      Also support cell selection and row selection modes.  In row selection
//      mode it acts like a pumped-up list widget.
//      Uses absolute cell references.
//
//      row -1 is defined as the row header
[...1523 lines suppressed...]
		veditor->show();
		Fl::focus(veditor);
		//veditor->take_focus();
		veditor->handle(FL_FOCUS);
		veditor->damage(FL_DAMAGE_ALL);
		veditor->redraw();
	    }
	}
    }
    if (!veditor) {
	vediting = false;
	edit_row = -1;
	edit_col = -1;
    }
    if (!veditor && wfocused) {
	Fl::focus(this);
	//    take_focus();
	handle(FL_FOCUS);
    }
}

--- NEW FILE: Flv_CStyle.cxx ---
//      ======================================================================
//      File:    Flv_CStyle.cxx - Flv_CStyle implementation
//      Program: Flv_Style - FLTK Virtual List/Table Styles Widget
//      Version: 0.1.0
//      Started: 11/21/99
//
//      Copyright (C) 1999 Laurence Charlton
//
//      Description:
//      The complex styles will be used in the complex table.  Should be basically
//      the same as Flv_Style with x,y positional data.
//      ======================================================================

#include <Flek/Flv_CStyle.H>
#include <stdio.h>
#ifdef WIN32
#include <mem.h>
#else
#include <memory.h>
#endif

#define ADDSIZE 10

//      **********************************************************************
//      Routines for Flv_CStyle
//
//      Defines the additional properties for a complex layout table.
//      A complex layout table allows the placement of cells (columns) within
//      a row.  The overall layout is used to determine minimum row heights/
//      widths, etc.
//      **********************************************************************
Flv_CStyle::Flv_CStyle():
Flv_Style()
{
    vx = 0;
    vy = 0;
    width(0);
    height(0);
}

//      Set x
int
Flv_CStyle::x(int n)
{
    if (n < 0)
	n = 0;
    return (vx = n);
}

//      Set y
int
Flv_CStyle::y(int n)
{
    if (n < 0)
	n = 0;
    return (vy = n);
}


const Flv_CStyle &
Flv_CStyle::operator=(const Flv_CStyle & n)
{
    Flv_Style::operator=(n);
    vx = n.vx;
    vy = n.vy;
    return *this;
}

--- NEW FILE: Fl_Toggle_Node.cxx ---
#include <Flek/Fl_Toggle_Node.H>

--- NEW FILE: Fl_App_Window.cxx ---
#include <stdio.h>
#include <stdlib.h>

#include <FL/Fl.H>
#include <FL/Fl_Window.H>	// needed by FLTK2
#include <FL/x.H>
#include <FL/fl_draw.H>
#include <Flek/Fl_App_Window.H>

// #define FL_APP_WINDOW_DEBUG

Fl_App_Window::Fl_App_Window(int x, int y, int w, int h, const char *l):
Fl_Window(x, y, w, h, l)
{
    create_app_window(w, h, l);
}

Fl_App_Window::Fl_App_Window(int w, int h, const char *l):
Fl_Window(w, h, l)
{
    create_app_window(w, h, l);
}

Fl_App_Window::~Fl_App_Window()
{
    free(dockable_windows);
}

void
Fl_App_Window::create_app_window(int w, int h, const char *l)
{
#ifdef FL_APP_WINDOW_DEBUG
    printf("Fl_App_Window::create_app_window win %p %dx%d\n", this, w, h);
#endif
    // Make room for the list of dockable windows.
    dockable_windows_capacity = 4;
    dockable_windows =
	(Fl_Dockable_Window **) malloc(sizeof(Fl_Dockable_Window *) *
				       dockable_windows_capacity);
    dockable_windows_size = 0;

    // Contents window and docked windows will complete obscure the
    // toplevel window, so set it to no box.
    Fl_Window::box(FL_NO_BOX);

    // Create the pack that holds the contents window and docked windows.
    // Contents window and docked windows will complete obscure the
    // the pack area, so set it to no box.
    _pack = new Fl_Pack(0, 0, w, h, "Fl_App_Window::pack");
    _pack->type(Fl_Pack::VERTICAL);
    _pack->box(FL_NO_BOX);

    // Create the contents window.
    _contents = new Fl_Window(0, 0, w, h, "Fl_App_Window::contents");

    // Contents area is the resizable for the pack group.
    // As dockables get added and removed, contents resizes.
    // Now, wouldn't that be just dandy?
    // However, Fl_Pack apparently doesn't work that way,
    // at least AFAICT at this point.
    // _pack->resizable(_contents);

    // Pack group is the resizable for the window.
    // Maybe this isn't so cool, as it makes the window resizable,
    // which maybe isn't what everyone wants.
    // Code in resize below emulates this instead.
    // resizable(_pack);

#ifdef FL_APP_WINDOW_DEBUG
    // Turn on borders so we can see what is what.
    Fl_Window::box(FL_BORDER_BOX);
    Fl_Window::color(FL_WHITE);
    _pack->box(FL_DOWN_BOX);
    _contents->box(FL_UP_BOX);
    _contents->color(FL_LIGHT3);
#endif
}

int
Fl_App_Window::handle(int event)
{

    if (event == FL_UNDOCK) {
#ifdef FL_APP_WINDOW_DEBUG
	printf("Fl_App_Window::handle - undock\n");
#endif
	repack();
	return 1;
    }

    if (event == FL_DOCK) {
	// Isn't it in this windows list of dockable widows?
	if (!may_dock(Fl_Dockable_Window::current))
	    // Don't dock it.
	    return 1;

	int dx = Fl::event_x_root();
	int dy = Fl::event_y_root();
	int ex = x_root();
	int ey = y_root();

	// Check to see if we can dock along any of 
	// the pack boundaries.

	// This code should probably go into Pack_2's handle:
//    Fl_Widget*const* a = _pack->array();
	for (int i = 0; i <= _pack->children(); i++) {
	    int cY;

	    if (i == _pack->children())
		cY = h();
	    else {
//        Fl_Widget* o = *a++;
		Fl_Widget *o = _pack->child(i);
		cY = o->y();
	    }

	    if ((dx < (ex + FL_DOCK_DELTA + w()))	// xmax
		&& (dx > (ex - FL_DOCK_DELTA))	// xmin 
		&& (dy < (ey + FL_DOCK_DELTA + cY))	// ymax
		&& (dy > (ey - FL_DOCK_DELTA + cY)))	// ymin
	    {
#ifdef FL_APP_WINDOW_DEBUG
		printf("Fl_App_Window::handle - dock\n");
#endif
		add_dockable(Fl_Dockable_Window::current, i);
		return 1;
	    }
	}
	return 0;
    }
    return Fl_Window::handle(event);
}

void
Fl_App_Window::add(Fl_Widget * w)
{
    // Anything added to Fl_App should actually get 
    // added to the contents group.
    _contents->add(w);
}

bool
Fl_App_Window::may_dock(Fl_Dockable_Window * W)
{
    // Is the dockable window in the dockable_windows list?
    for (int i = 0; i < dockable_windows_size; i++)
	if (dockable_windows[i] == W)
	    return true;
    return false;
}

void
Fl_App_Window::accept_dockable(Fl_Dockable_Window * W)
{
    // Does this dockable window already have permission to dock?
    // In other words, is it already in the list?
    if (may_dock(W))
	// Already in the list, don't add it again.
	return;

    // Is there room left in the list?
    if (dockable_windows_size >= dockable_windows_capacity) {
	// Out of space.  That's okay.  We'll make more.
	dockable_windows_capacity *= 2;
	dockable_windows = (Fl_Dockable_Window **) realloc(dockable_windows,
							   sizeof
							   (Fl_Dockable_Window
							    *) *
							   dockable_windows_capacity);
    }
    // Add it to the list.
    dockable_windows[dockable_windows_size++] = W;
}

void
Fl_App_Window::add_dockable(Fl_Dockable_Window * W, int pos)
{
    // Add the dockable window to this window's list of dockable windows.
    accept_dockable(W);

    // Dock the dockable window on this window.
    Fl_Dockable_Window::current = W;

    if (W->shown())
	W->hide();

    _pack->insert(*W, pos);
    repack();

    W->docked(1);

    if (shown())
	W->show();
}

void
Fl_App_Window::show()
{
#ifdef FL_APP_WINDOW_DEBUG
    printf("Fl_App_Window::show() win %p\n", this);
#endif

    // Show ourself.
    Fl_Window::show();

    // Show our dockable windows.
    for (int i = 0; i < dockable_windows_size; i++)
	dockable_windows[i]->show();
}

void
Fl_App_Window::hide()
{
    for (int i = 0; i < dockable_windows_size; i++)
	dockable_windows[i]->hide();
    Fl_Window::hide();
}

void
Fl_App_Window::flush()
{
#ifdef FL_APP_WINDOW_DEBUG
    printf("Fl_App_Window::flush() win %p\n", this);
#endif

    make_current();
    Fl_X *i = Fl_X::i(this);
    fl_clip_region(i->region);
    i->region = 0;
    // Based on my testing, this draw() is required.  bdl
    draw();
}

void
Fl_App_Window::repack()
{
    // Figure how much space everything but the contents takes up.
    int children_w = 0;
    int children_h = 0;
    for (int i = 0; i < _pack->children(); i++) {
	if (_pack->child(i) == _contents)
	    continue;
	// HACK: don't consider width since packing is vertical.
	// children_w += _pack->child(i)->w();
	children_h += _pack->child(i)->h();
#ifdef FL_APP_WINDOW_DEBUG
	printf("Fl_App_Window::repack win %p child %d size %dx%d\n",
	       this, i, _pack->child(i)->w(), _pack->child(i)->h());
#endif
    }

    // Make contents fill all remaining space.
    _contents->resize(0, 0, w() - children_w, h() - children_h);

    // Resize the pack to fill the window.
    _pack->resize(0, 0, w(), h());

#ifdef FL_APP_WINDOW_DEBUG
    printf("Fl_App_Window::repack win %p pack %dx%d contents %dx%d\n",
	   this, w(), h(), w() - children_w, h() - children_h);
#endif
}

void
Fl_App_Window::resize(int X, int Y, int W, int H)
{
#ifdef FL_APP_WINDOW_DEBUG
    printf("Fl_App_Window::resize() win %p %dx%d+%d+%d\n", this, W, H, X, Y);
#endif
    Fl_Widget::resize(X, Y, W, H);
    repack();
}

#if FL_MAJOR_VERSION == 2
void
Fl_App_Window::layout()
{
    printf("layout called\n");
    printf("1AppWin- x:%d y:%d w:%d h:%d\n", x(), y(), w(), h());
    printf("1pack- x:%d y:%d w:%d h:%d\n", _pack->x(), _pack->y(), _pack->w(),
	   _pack->h());
    printf("1contents- x:%d y:%d w:%d h:%d\n", _contents->x(), _contents->y(),
	   _contents->w(), _contents->h());

    repack();

    printf("2AppWin- x:%d y:%d w:%d h:%d\n", x(), y(), w(), h());
    printf("2pack- x:%d y:%d w:%d h:%d\n", _pack->x(), _pack->y(), _pack->w(),
	   _pack->h());
    printf("2contents- x:%d y:%d w:%d h:%d\n", _contents->x(), _contents->y(),
	   _contents->w(), _contents->h());
}
#endif

--- NEW FILE: FFile.cxx ---
#include <Flek/FFile.H>
#include <FL/filename.H>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>		// realpath
#include <stdio.h>		// tmpnam
#include <sys/stat.h>

void
lo_to_hi(ulong * buffer, int len)
{
//  return;
    char *cbuffer = (char *) buffer;
    register ulong value;
    for (register int i = 0; i < len; i++, cbuffer += 4) {
	value = buffer[i];
	cbuffer[0] = ((value >> 24) & 0xff);
	cbuffer[1] = ((value >> 16) & 0xff);
	cbuffer[2] = ((value >> 8) & 0xff);
	cbuffer[3] = ((value & 0xff));
    }
}

void
FFile::open(char *filename, FFileMode mode)
{
    char *m = 0;

    switch (mode) {
    case FFileNull:
	m = "";
	break;
    case FFileRead:
	m = "r";
	break;
    case FFileReadPlus:
	m = "r+";
	break;
    case FFileWrite:
	m = "w";
	break;
    case FFileWritePlus:
	m = "w+";
	break;
    case FFileAppend:
	m = "a";
	break;
    case FFileAppendPlus:
	m = "a+";
	break;
    }

    Fd = fopen(filename, m);

    if (!Fd)
	Error = 1;
    else
	Error = 0;
}

--- NEW FILE: FSocket.cxx ---
#ifdef WIN32
#include "FSocket_Win32.cxx"
#else
#include "FSocket_Posix.cxx"
#endif

--- NEW FILE: Makefile ---
### Flek Makefile
# This makefile has been changed to adjust to the Pixil build environement.
# Check the readme for details on the changes that we have made

LIB_STATIC=libflek.a
LIB_SHARED=libflek.so

CPPFILES= FDate.cxx FSocket.cxx FFile.cxx FVector.cxx \
	FImage.cxx FSGI.cxx FPNM.cxx Fl_App_Window.cxx \
	Fl_Better_Window.cxx Fl_Calendar.cxx Fl_Dockable_Window.cxx \
	Fl_Stock.cxx Fl_Toggle_Node_Base.cxx Fl_Toggle_Node.cxx \
	Fl_Toggle_Tree_Base.cxx Fl_Toggle_Tree.cxx Flv_CStyle.cxx \
	Flv_Style.cxx Flv_List.cxx Flv_Table.cxx Flve_Check_Button.cxx \
	Flve_Input.cxx Flve_Combo.cxx Fl_Time.cxx

OBJS = $(CPPFILES:.cxx=.o)

CFLAGS ?=
CFLAGS += -DPIXIL

ifeq ($(CROSS_COMPILE),y)
CFLAGS += -fpermissive
endif

INCLUDES=-I. -I../ 

include $(BASE_DIR)/Rules.make

--- NEW FILE: FImage.cxx ---
#include <Flek/math.H>
#include <Flek/FImage.H>
#include <string.h>
//#include <iostream.h>
//#include <fstream.h>

typedef unsigned long ulong;
typedef unsigned long *ulongPtr;
typedef unsigned short ushort;
typedef unsigned short *ushortPtr;
typedef unsigned char uchar;
typedef unsigned char *ucharPtr;

#define INT_MULT(a,b,t)  ((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
#define INT_BLEND(a,b,alpha,tmp)  (INT_MULT((a)-(b), alpha, tmp) + (b))

FImage::FImage()
{
    Data = 0;
    W = 0;
    H = 0;
    Channels = 4;
}

FImage::FImage(int w, int h, int channels)
{
    W = w;
    H = h;
    Channels = channels;
    Data = new uchar[W * H * Channels];
}

FImage::FImage(FImage * src)
{
    W = src->width();
    H = src->height();
    Channels = src->channels();
    Data = new uchar[W * H * Channels];
    memcpy((void *) Data, (void *) *(src->begin()), W * H * Channels);
}

FImage::~FImage()
{
    if (Data)
	delete[]Data;
}

void
FImage::channels(int dest_channels)
{
    uchar *src = Data;
    int src_channels = Channels;
    int k_max = min(src_channels, dest_channels);
    uchar *r = new uchar[W * H * dest_channels];
    uchar *dest = r;

    unsigned char *end = dest + dest_channels * W * H;
    for (; dest < end; dest += dest_channels, src += src_channels) {
	for (int k = 0; k < k_max; k++)
	    dest[k] = src[k];
    }

    if ((Channels == 3) && (dest_channels == 4)) {
	dest = r;
	for (; dest < end; dest += dest_channels)
	    dest[3] = 255;
    }

    delete[]Data;
    Data = r;
    Channels = dest_channels;
}

void
FImage::flip_vertical()
{
    uchar row[Channels * W];
    for (int i = 0; i < H / 2; i++) {
	memcpy(row, &Data[Channels * W * i], Channels * W);
	memcpy(&Data[Channels * W * i], &Data[Channels * W * (H - i - 1)],
	       Channels * W);
	memcpy(&Data[Channels * W * (H - i - 1)], row, Channels * W);
    }
}

void
FImage::clear(uchar r, uchar g, uchar b, uchar a)
{
    int i;
    if (Channels >= 4)
	for (i = 0; i < Channels * W * H; i += Channels) {
	    Data[i] = r;
	    Data[i + 1] = g;
	    Data[i + 2] = b;
	    Data[i + 3] = a;
    } else if (Channels == 3) {
	for (i = 0; i < Channels * W * H; i += Channels) {
	    Data[i] = r;
	    Data[i + 1] = g;
	    Data[i + 2] = b;
	}
    } else if (Channels == 2) {
	for (i = 0; i < Channels * W * H; i += Channels) {
	    Data[i] = r;
	    Data[i + 1] = g;
	}
    } else if (Channels == 1) {
	for (i = 0; i < Channels * W * H; i += Channels)
	    Data[i] = r;
    }

}

FImage *
FImage::scale(int x, int y)
{
    FImage *r = new FImage(x, y, Channels);

    uchar *dest = *(r->begin());
    for (int i = 0; i < y; i++)
	for (int j = 0; j < x; j++)
	    for (int k = 0; k < Channels; k++, dest++) {
		float tx = ((float) j / (float) x);
		float ty = ((float) i / (float) y);
		int ix = (int) (tx * W);
		int iy = (int) (ty * H);
		dest[0] = Data[iy * Channels * W + ix * Channels + k];
	    }

    return r;
}

/*
 * All operations are done "in-place" on image A and do not return a 
 * new image for efficiency.  If you want a new image, copy image A
 * and then work on the copy.
 */

void
composite(unsigned char *dest,
	  const unsigned char *src,
	  int opacity, int length, int dest_channels, int src_channels)
{
    int a;
    register long t1;
    unsigned char *end = dest + dest_channels * length;
    for (; dest < end; dest += dest_channels, src += src_channels) {
	if (src_channels > 3) {
	    a = INT_MULT(src[3], opacity, t1);
	    // b + (1-b)*a
	    if (dest_channels > 3)
		dest[3] = min(src[3] + INT_MULT(255 - src[3], dest[3], t1), 255);	//INT_MULT(dest[3], a, t1); //dest[3] = 255;
	} else
	    a = opacity;
	dest[0] = INT_BLEND(src[0], dest[0], a, t1);
	dest[1] = INT_BLEND(src[1], dest[1], a, t1);
	dest[2] = INT_BLEND(src[2], dest[2], a, t1);
    }
}

FImage *
composite(FImage * A, FImage * B, int xo, int yo, float value)
{
    int xi = max(xo, 0);
    int yi = max(yo, 0);
    int xf = min(max(xo + B->width(), 0), A->width());
    int yf = min(max(yo + B->height(), 0), A->height());

    for (int row = yi; row < yf; row++)
	composite(*(*A) (xi, row), *(*B) (xi - xo, row - yo),
		  (int) (value * 255), xf - xi, A->channels(), B->channels());
    return A;
}

void
add(unsigned char *dest,
    const unsigned char *src,
    int opacity, int length, int dest_channels, int src_channels)
{
    int a;
    register long t1;
    unsigned char *end = dest + dest_channels * length;
    for (; dest < end; dest += dest_channels, src += src_channels) {
	if (src_channels > 3) {
	    a = INT_MULT(src[3], opacity, t1);
	    if (dest_channels > 3)
		dest[3] = 255;
	} else
	    a = opacity;
	dest[0] =
	    INT_BLEND(clamp_upper(src[0] + dest[0], 255), dest[0], a, t1);
	dest[1] =
	    INT_BLEND(clamp_upper(src[1] + dest[1], 255), dest[1], a, t1);
	dest[2] =
	    INT_BLEND(clamp_upper(src[2] + dest[2], 255), dest[2], a, t1);
    }
}

FImage *
add(FImage * A, FImage * B, int xo, int yo, float value)
{
    int xi = max(xo, 0);
    int yi = max(yo, 0);
    int xf = min(max(xo + B->width(), 0), A->width());
    int yf = min(max(yo + B->height(), 0), A->height());

    for (int row = yi; row < yf; row++)
	add(*(*A) (xi, row), *(*B) (xi - xo, row - yo), (int) (value * 255),
	    xf - xi, A->channels(), B->channels());
    return A;
}

void
subtract(unsigned char *dest,
	 const unsigned char *src,
	 int opacity, int length, int dest_channels, int src_channels)
{
    int a;
    register long t1;
    unsigned char *end = dest + dest_channels * length;
    for (; dest < end; dest += dest_channels, src += src_channels) {
	if (src_channels > 3) {
	    a = INT_MULT(src[3], opacity, t1);
	    if (dest_channels > 3)
		dest[3] = 255;
	} else
	    a = opacity;
	dest[0] = INT_BLEND(clamp_lower(dest[0] - src[0], 0), dest[0], a, t1);
	dest[1] = INT_BLEND(clamp_lower(dest[1] - src[1], 0), dest[1], a, t1);
	dest[2] = INT_BLEND(clamp_lower(dest[2] - src[2], 0), dest[2], a, t1);
    }
}

FImage *
subtract(FImage * A, FImage * B, int xo, int yo, float value)
{
    int xi = max(xo, 0);
    int yi = max(yo, 0);
    int xf = min(max(xo + B->width(), 0), A->width());
    int yf = min(max(yo + B->height(), 0), A->height());

    for (int row = yi; row < yf; row++)
	subtract(*(*A) (xi, row), *(*B) (xi - xo, row - yo),
		 (int) (value * 255), xf - xi, A->channels(), B->channels());
    return A;
}

void
difference(unsigned char *dest,
	   const unsigned char *src,
	   int opacity, int length, int dest_channels, int src_channels)
{
    int a;
    register long t1;
    unsigned char *end = dest + dest_channels * length;
    for (; dest < end; dest += dest_channels, src += src_channels) {
	if (src_channels > 3) {
	    a = INT_MULT(src[3], opacity, t1);
	    if (dest_channels > 3)
		dest[3] = 255;
	} else
	    a = opacity;
	dest[0] =
	    INT_BLEND(max(dest[0], src[0]) - min(dest[0], src[0]), dest[0], a,
		      t1);
	dest[1] =
	    INT_BLEND(max(dest[1], src[1]) - min(dest[1], src[1]), dest[1], a,
		      t1);
	dest[2] =
	    INT_BLEND(max(dest[2], src[2]) - min(dest[2], src[2]), dest[2], a,
		      t1);
    }
}

FImage *
difference(FImage * A, FImage * B, int xo, int yo, float value)
{
    int xi = max(xo, 0);
    int yi = max(yo, 0);
    int xf = min(max(xo + B->width(), 0), A->width());
    int yf = min(max(yo + B->height(), 0), A->height());

    for (int row = yi; row < yf; row++)
	difference(*(*A) (xi, row), *(*B) (xi - xo, row - yo),
		   (int) (value * 255), xf - xi, A->channels(),
		   B->channels());
    return A;
}

void
lighten_only(unsigned char *dest,
	     const unsigned char *src,
	     int opacity, int length, int dest_channels, int src_channels)
{
    int a;
    register long t1;
    unsigned char *end = dest + dest_channels * length;
    for (; dest < end; dest += dest_channels, src += src_channels) {
	if (src_channels > 3) {
	    a = INT_MULT(src[3], opacity, t1);
	    if (dest_channels > 3)
		dest[3] = 255;
	} else
	    a = opacity;
	dest[0] = INT_BLEND(max(dest[0], src[0]), dest[0], a, t1);
	dest[1] = INT_BLEND(max(dest[1], src[1]), dest[1], a, t1);
	dest[2] = INT_BLEND(max(dest[2], src[2]), dest[2], a, t1);
    }
}

FImage *
lighten_only(FImage * A, FImage * B, int xo, int yo, float value)
{
    int xi = max(xo, 0);
    int yi = max(yo, 0);
    int xf = min(max(xo + B->width(), 0), A->width());
    int yf = min(max(yo + B->height(), 0), A->height());

    for (int row = yi; row < yf; row++)
	lighten_only(*(*A) (xi, row), *(*B) (xi - xo, row - yo),
		     (int) (value * 255), xf - xi, A->channels(),
		     B->channels());
    return A;
}

void
darken_only(unsigned char *dest,
	    const unsigned char *src,
	    int opacity, int length, int dest_channels, int src_channels)
{
    int a;
    register long t1;
    unsigned char *end = dest + dest_channels * length;
    for (; dest < end; dest += dest_channels, src += src_channels) {
	if (src_channels > 3) {
	    a = INT_MULT(src[3], opacity, t1);
	    if (dest_channels > 3)
		dest[3] = 255;
	} else
	    a = opacity;
	dest[0] = INT_BLEND(min(dest[0], src[0]), dest[0], a, t1);
	dest[1] = INT_BLEND(min(dest[1], src[1]), dest[1], a, t1);
	dest[2] = INT_BLEND(min(dest[2], src[2]), dest[2], a, t1);
    }
}

FImage *
darken_only(FImage * A, FImage * B, int xo, int yo, float value)
{
    int xi = max(xo, 0);
    int yi = max(yo, 0);
    int xf = min(max(xo + B->width(), 0), A->width());
    int yf = min(max(yo + B->height(), 0), A->height());

    for (int row = yi; row < yf; row++)
	darken_only(*(*A) (xi, row), *(*B) (xi - xo, row - yo),
		    (int) (value * 255), xf - xi, A->channels(),
		    B->channels());
    return A;
}

void
divide(unsigned char *dest,
       const unsigned char *src,
       int opacity, int length, int dest_channels, int src_channels)
{
    int a;
    register long t1;
    unsigned char *end = dest + dest_channels * length;
    for (; dest < end; dest += dest_channels, src += src_channels) {
	if (src_channels > 3) {
	    a = INT_MULT(src[3], opacity, t1);
	    if (dest_channels > 3)
		dest[3] = min(dest[3], src[3]);
	} else
	    a = opacity;
	dest[0] =
	    INT_BLEND(min((dest[0] * 256) / (1 + src[0]), 255), dest[0], a,
		      t1);
	dest[1] =
	    INT_BLEND(min((dest[1] * 256) / (1 + src[1]), 255), dest[1], a,
		      t1);
	dest[2] =
	    INT_BLEND(min((dest[2] * 256) / (1 + src[2]), 255), dest[2], a,
		      t1);
    }
}

FImage *
divide(FImage * A, FImage * B, int xo, int yo, float value)
{
    int xi = max(xo, 0);
    int yi = max(yo, 0);
    int xf = min(max(xo + B->width(), 0), A->width());
    int yf = min(max(yo + B->height(), 0), A->height());

    for (int row = yi; row < yf; row++)
	divide(*(*A) (xi, row), *(*B) (xi - xo, row - yo),
	       (int) (value * 255), xf - xi, A->channels(), B->channels());
    return A;
}

void
multiply(unsigned char *dest,
	 const unsigned char *src,
	 int opacity, int length, int dest_channels, int src_channels)
{
    int a;
    register long t1;
    unsigned char *end = dest + dest_channels * length;
    for (; dest < end; dest += dest_channels, src += src_channels) {
	if (src_channels > 3) {
	    a = INT_MULT(src[3], opacity, t1);
	    if (dest_channels > 3)
		dest[3] = min(dest[3], src[3]);
	} else
	    a = opacity;
	dest[0] = INT_BLEND(INT_MULT(src[0], dest[0], t1), dest[0], a, t1);
	dest[1] = INT_BLEND(INT_MULT(src[1], dest[1], t1), dest[1], a, t1);
	dest[2] = INT_BLEND(INT_MULT(src[2], dest[2], t1), dest[2], a, t1);
    }
}

FImage *
multiply(FImage * A, FImage * B, int xo, int yo, float value)
{
    int xi = max(xo, 0);
    int yi = max(yo, 0);
    int xf = min(max(xo + B->width(), 0), A->width());
    int yf = min(max(yo + B->height(), 0), A->height());

    for (int row = yi; row < yf; row++)
	multiply(*(*A) (xi, row), *(*B) (xi - xo, row - yo),
		 (int) (value * 255), xf - xi, A->channels(), B->channels());
    return A;
}

void
screen(unsigned char *dest,
       const unsigned char *src,
       int opacity, int length, int dest_channels, int src_channels)
{
    int a;
    register long t1;
    unsigned char *end = dest + dest_channels * length;
    for (; dest < end; dest += dest_channels, src += src_channels) {
	if (src_channels > 3) {
	    a = INT_MULT(src[3], opacity, t1);
	    if (dest_channels > 3)
		dest[3] = min(dest[3], src[3]);
	} else
	    a = opacity;
	dest[0] =
	    INT_BLEND(255 - INT_MULT(255 - src[0], 255 - dest[0], t1),
		      dest[0], a, t1);
	dest[1] =
	    INT_BLEND(255 - INT_MULT(255 - src[1], 255 - dest[1], t1),
		      dest[1], a, t1);
	dest[2] =
	    INT_BLEND(255 - INT_MULT(255 - src[2], 255 - dest[2], t1),
		      dest[2], a, t1);
    }
}

FImage *
screen(FImage * A, FImage * B, int xo, int yo, float value)
{
    int xi = max(xo, 0);
    int yi = max(yo, 0);
    int xf = min(max(xo + B->width(), 0), A->width());
    int yf = min(max(yo + B->height(), 0), A->height());

    for (int row = yi; row < yf; row++)
	screen(*(*A) (xi, row), *(*B) (xi - xo, row - yo),
	       (int) (value * 255), xf - xi, A->channels(), B->channels());
    return A;
}

void
overlay(unsigned char *dest,
	const unsigned char *src,
	int opacity, int length, int dest_channels, int src_channels)
{
    int a;
    register long t1;
    unsigned char *end = dest + dest_channels * length;
    for (; dest < end; dest += dest_channels, src += src_channels) {
	if (src_channels > 3) {
	    a = INT_MULT(src[3], opacity, t1);
	    if (dest_channels > 3)
		dest[3] = min(dest[3], src[3]);
	} else
	    a = opacity;
	dest[0] =
	    INT_BLEND(INT_MULT
		      (dest[0],
		       dest[0] + INT_MULT(2 * src[0], 255 - dest[0], t1), t1),
		      dest[0], a, t1);
	dest[1] =
	    INT_BLEND(INT_MULT
		      (dest[1],
		       dest[0] + INT_MULT(2 * src[1], 255 - dest[1], t1), t1),
		      dest[1], a, t1);
	dest[2] =
	    INT_BLEND(INT_MULT
		      (dest[2],
		       dest[0] + INT_MULT(2 * src[2], 255 - dest[2], t1), t1),
		      dest[2], a, t1);
    }
}

FImage *
overlay(FImage * A, FImage * B, int xo, int yo, float value)
{
    int xi = max(xo, 0);
    int yi = max(yo, 0);
    int xf = min(max(xo + B->width(), 0), A->width());
    int yf = min(max(yo + B->height(), 0), A->height());

    for (int row = yi; row < yf; row++)
	overlay(*(*A) (xi, row), *(*B) (xi - xo, row - yo),
		(int) (value * 255), xf - xi, A->channels(), B->channels());
    return A;
}

--- NEW FILE: Flve_Check_Button.cxx ---
//      ======================================================================
//      File:    Flve_Input.cxx - Flve_Input implementation
//      Library: flvw - FLTK Virtual widget library
//      Version: 0.1.0
//      Started: 01/12/2000
//
//      Copyright (C) 1999 Laurence Charlton
//
//      Description:
//      Flve_Input implements cell text editing for a list/table.
//      ======================================================================

#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <Flek/Flve_Check_Button.H>

int
Flve_Check_Button::handle(int event)
{
    int stat;

    stat = Fl_Check_Button::handle(event);
    if (!stat) {
	switch (event) {
	case FL_FOCUS:
	case FL_UNFOCUS:
	    return 1;

	case FL_KEYBOARD:
	    switch (Fl::event_key()) {
	    case ' ':
		value(!value());
		redraw();
		return 1;
	    }
	    break;
	}

	if (owner && event == FL_KEYBOARD)
	    if (owner->handle(FL_SHORTCUT))
		return 1;
    }
    return stat;
}

void
draw_flve_check_button(int X, int Y, int W, int H, Flve_Check_Button * b,
		       char *v)
{
    int x, y, w, h;
    w = W;
    h = H;
    if (H < W)
	w = h;
    else
	h = w;
    x = X;			// + (W-w)/2;
    y = Y;			// + (H-h)/2;
    x++;
    y++;
    w -= 2;
    h -= 2;
    fl_color(b ? b->color() : (Fl_Color) (FL_GRAY_RAMP + 17));
    fl_rectf(X, Y, W, H);
    if (b) {
#if FL_MAJOR_VERSION == 1
	if (*v == '1')
	    fl_draw_box(b->down_box(), x, y, w, h, b->selection_color());
	else
	    fl_draw_box(b->down_box(), x, y, w, h, b->color());
#endif
    } else {
	if (*v == '1')
	    fl_draw_box(FL_THIN_DOWN_BOX, x, y, w, h, FL_RED);
	else
	    fl_draw_box(FL_THIN_DOWN_BOX, x, y, w, h,
			(Fl_Color) (FL_GRAY_RAMP + 17));
    }
}

--- NEW FILE: Fl_Time.cxx ---
// Fl_Time.cxx
// Source file for the time widget class
//
// Copyright (C) 2000 Softfield Research Ltd.
//
// 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.

#include <stdio.h>
#include <string.h>
#include <time.h>

#include <Flek/Fl_Time.H>

Fl_Time::Fl_Time(int x, int y, int w, int h, char *l):
Fl_Group(x, y, w, h, l)
{
    int button_width = (int) (w / 7);

    input_time = new Fl_Input(x, y, w - button_width * 4, h, 0);
    input_time->callback(input_changed_cb, this);
    input_time->when(FL_WHEN_CHANGED);
    input_time->textsize(10);

    button_decrease_hour =
	new Fl_Repeat_Button(x + w - 4 * button_width, y, button_width, h,
			     "H-");
    button_decrease_hour->callback(button_cb, this);
    button_decrease_hour->labelsize(10);

    button_increase_hour =
	new Fl_Repeat_Button(x + w - 3 * button_width, y, button_width, h,
			     "H+");
    button_increase_hour->callback(button_cb, this);
    button_increase_hour->labelsize(10);

    button_decrease_minute =
	new Fl_Repeat_Button(x + w - 2 * button_width, y, button_width, h,
			     "M-");
    button_decrease_minute->callback(button_cb, this);
    button_decrease_minute->labelsize(10);

    button_increase_minute =
	new Fl_Repeat_Button(x + w - button_width, y, button_width, h, "M+");
    button_increase_minute->callback(button_cb, this);
    button_increase_minute->labelsize(10);

    end();

    type(FL_TIME_12HOUR);
    current_time();
}

void
Fl_Time::current_time()
{
    struct tm *display_time_tm;

    gettimeofday(&current_tv, 0);
    display_tv.tv_sec = current_tv.tv_sec;
    display_tv.tv_usec = current_tv.tv_usec;
    display_time_tm = localtime(&current_tv.tv_sec);

    if (type() == FL_TIME_24HOUR)
	strftime(time_string, 19, "%2H:%2M", display_time_tm);
    else
	strftime(time_string, 19, "%2I:%2M %p", display_time_tm);

    input_time->value(time_string);
}

void
Fl_Time::refresh()
{
    long different;
    struct tm *display_time_tm;

    if (valid()) {
	different = -display_tv.tv_sec + current_tv.tv_sec;
	gettimeofday(&current_tv, 0);

	display_tv.tv_sec = current_tv.tv_sec - different;
	display_time_tm = localtime(&display_tv.tv_sec);

	if (type() == FL_TIME_24HOUR)
	    strftime(time_string, 19, "%2H:%2M", display_time_tm);
	else
	    strftime(time_string, 19, "%2I:%2M %p", display_time_tm);

	input_time->value(time_string);
    }
}

int
Fl_Time::hour()
{
    struct tm *display_time_tm;

    display_time_tm = localtime(&display_tv.tv_sec);
    return display_time_tm->tm_hour;
}

int
Fl_Time::minute()
{
    struct tm *display_time_tm;

    display_time_tm = localtime(&display_tv.tv_sec);
    return display_time_tm->tm_min;
}

void
Fl_Time::redisplay()
{
    struct tm *display_time_tm;

    display_time_tm = localtime(&display_tv.tv_sec);

    if (type() == FL_TIME_24HOUR)
	strftime(time_string, 19, "%2H:%2M", display_time_tm);
    else
	strftime(time_string, 19, "%2I:%2M %p", display_time_tm);

    input_time->value(time_string);
}

void
Fl_Time::hour(int value)
{
    struct tm *display_time_tm;

    display_time_tm = localtime(&display_tv.tv_sec);
    display_time_tm->tm_hour = value;
    display_tv.tv_sec = mktime(display_time_tm);
}

void
Fl_Time::minute(int value)
{
    struct tm *display_time_tm;

    display_time_tm = localtime(&display_tv.tv_sec);
    if (value < 0) {
	display_time_tm->tm_min = 59;
    } else if (value >= 0 && value <= 59) {
	display_time_tm->tm_min = value;
    } else if (value > 59) {
	display_time_tm->tm_min = 0;
    }
    display_time_tm->tm_sec = 0;
    display_tv.tv_sec = mktime(display_time_tm);
}

void
Fl_Time::value(int h, int m)
{
    hour(h);
    minute(m);
}

bool
Fl_Time::valid()
{
    int h, m;
    char a[5];

    if (type() == FL_TIME_12HOUR) {
	if (sscanf(input_time->value(), "%d:%d %s", &h, &m, a) == 3) {
	    if (h >= 1 && h <= 12 && m >= 0 && m <= 59
		&& (strcasecmp(a, "am") == 0 || strcasecmp(a, "pm") == 0)) {
		last_valid = true;
		return true;
	    }
	}
    } else {
	if (sscanf(input_time->value(), "%d:%d", &h, &m) == 2) {
	    if (h >= 0 && h <= 23 && m >= 0 && m <= 59) {
		last_valid = true;
		return true;
	    }
	}
    }
    last_valid = false;
    return false;
}

void
Fl_Time::input_changed_cb(Fl_Widget * widget, void *data)
{
    Fl_Time *t = (Fl_Time *) data;
    int h, m;
    char a[5];

    if (t->valid()) {
	if (t->type() == FL_TIME_12HOUR) {
	    sscanf(t->input_time->value(), "%d:%d %2s", &h, &m, a);
	    if (strcasecmp(a, "am") == 0) {
		if (h < 12) {
		    t->hour(h);
		} else {
		    t->hour(0);
		}
	    } else {
		if (h < 12) {
		    t->hour(h + 12);
		} else {
		    t->hour(12);
		}
	    }
	} else {
	    sscanf(t->input_time->value(), "%d:%d", &h, &m);
	    t->hour(h);
	}
	t->minute(m);
    }
    t->do_callback();
}

void
Fl_Time::button_cb(Fl_Widget * widget, void *data)
{
    Fl_Time *t = (Fl_Time *) data;

    if (widget == t->button_decrease_hour) {
	t->hour(t->hour() - 1);
    }
    if (widget == t->button_decrease_minute) {
	t->minute(t->minute() - 1);
    }
    if (widget == t->button_increase_minute) {
	t->minute(t->minute() + 1);
    }
    if (widget == t->button_increase_hour) {
	t->hour(t->hour() + 1);
    }
    t->redisplay();
    t->do_callback();
}

void
Fl_Time::textsize(int size)
{
    input_time->textsize(size);
}

void
Fl_Time::labelsize(int size)
{
    button_decrease_hour->labelsize(size);
    button_decrease_minute->labelsize(size);
    button_increase_minute->labelsize(size);
    button_increase_hour->labelsize(size);
    Fl_Group::labelsize(size);
}

void
Fl_Time::textfont(Fl_Font font)
{
    input_time->textfont(font);
}

void
Fl_Time::labelfont(Fl_Font font)
{
    button_decrease_hour->labelfont(font);
    button_decrease_minute->labelfont(font);
    button_increase_minute->labelfont(font);
    button_increase_hour->labelfont(font);
    Fl_Group::labelfont(font);
}

void
Fl_Time::textcolor(Fl_Color color)
{
    input_time->textcolor(color);
}

void
Fl_Time::labelcolor(Fl_Color color)
{
    button_decrease_hour->labelcolor(color);
    button_decrease_minute->labelcolor(color);
    button_increase_minute->labelcolor(color);
    button_increase_hour->labelcolor(color);
    Fl_Group::labelcolor(color);
}

int
Fl_Time::textsize()
{
    return input_time->textsize();
}

int
Fl_Time::labelsize()
{
    return button_decrease_hour->labelsize();
}

Fl_Font
Fl_Time::labelfont()
{
    return button_decrease_hour->labelfont();
}

Fl_Font
Fl_Time::textfont()
{
    return input_time->textfont();
}

Fl_Color
Fl_Time::labelcolor()
{
    return button_decrease_hour->labelcolor();
}

Fl_Color
Fl_Time::textcolor()
{
    return input_time->textcolor();
}

--- NEW FILE: FSocket_Posix.cxx ---
// FSocket was adapted from K.A. Knizhnik's very nice SAL library.

#if defined(__svr4__)
#define mutex system_mutex
#endif

#if defined(__FreeBSD__) || defined(__linux__) || defined(__CYGWIN__)
#include <sys/ioctl.h>
#else
#include <stropts.h>
#endif
#include <fcntl.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef __CYGWIN__
#include <netinet/tcp.h>
#endif
#include <unistd.h>
#include <errno.h>
extern "C"
{
#include <netdb.h>
}
#undef mutex

#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include "FSocket_Posix.H"

#include <signal.h>

#define MAX_HOST_NAME     256

char *
    FSocket_Posix::unix_socket_dir =
    "/tmp/";

class
    FSocket_Posix_library
{
  public:
    FSocket_Posix_library()
    {
	static struct sigaction
	    sigpipe_ignore;
	sigpipe_ignore.
	    sa_handler =
	    SIG_IGN;
	sigaction(SIGPIPE, &sigpipe_ignore, NULL);
    }
};

static FSocket_Posix_library
    unisock_lib;

int
FSocket_Posix::open(int listen_queue_size)
{
    char hostname[MAX_HOST_NAME];
    unsigned short port;
    char *p;

    assert(address != NULL);

    if ((p = strchr(address, ':')) == NULL
	|| unsigned (p - address) >= sizeof(hostname)
	|| sscanf(p + 1, "%hd", &port) != 1) {
	errcode = bad_address;
	return 0;
    }
    memcpy(hostname, address, p - address);
    hostname[p - address] = '\0';

    create_file = 0;

    union
    {
	sockaddr sock;
	sockaddr_in sock_inet;
	//char        name[MAX_HOST_NAME];
    }
    u;
    int sa_length;

    if (domain == sock_local_domain) {
	u.sock.sa_family = AF_UNIX;

	assert(strlen(unix_socket_dir) + strlen(address)
	       < MAX_HOST_NAME - offsetof(sockaddr, sa_data));

	sa_length = offsetof(sockaddr, sa_data) +
	    sprintf(u.sock.sa_data, "%s%s", unix_socket_dir, address);

	unlink(u.sock.sa_data);	// remove file if existed
	create_file = 1;
    } else {
	u.sock_inet.sin_family = AF_INET;
	u.sock_inet.sin_addr.s_addr = htonl(INADDR_ANY);
	u.sock_inet.sin_port = htons(port);
	sa_length = sizeof(sockaddr_in);
    }
    if ((fd = socket(u.sock.sa_family, SOCK_STREAM, 0)) < 0) {
	errcode = errno;
	return 0;
    }
    if (bind(fd, &u.sock, sa_length) < 0) {
	errcode = errno;
	::close(fd);
	return 0;
    }
    if (listen(fd, listen_queue_size) < 0) {
	errcode = errno;
	::close(fd);
	return 0;
    }
    errcode = ok;
    state = ss_open;
    return 1;
}

int
FSocket_Posix::valid()
{
    return errcode == ok;
}

void
FSocket_Posix::get_error_text(char *buf, size_t buf_size)
{
    char *msg;
    switch (errcode) {
    case ok:
	msg = "ok";
	break;
    case not_opened:
	msg = "socket not opened";
	break;
    case bad_address:
	msg = "bad address";
	break;
    case connection_failed:
	msg = "exceed limit of attempts of connection to server";
	break;
    case broken_pipe:
	msg = "connection is broken";
	break;
    case invalid_access_mode:
	msg = "invalid access mode";
	break;
    default:
	msg = strerror(errcode);
    }
    strncpy(buf, msg, buf_size);
}


FSocket *
FSocket_Posix::accept()
{
    int s;

    if (state != ss_open) {
	errcode = not_opened;
	return NULL;
    }

    while ((s =::accept(fd, NULL, NULL)) < 0 && errno == EINTR);

    if (s < 0) {
	errcode = errno;
	return NULL;
    } else if (state != ss_open) {
	errcode = not_opened;
	return NULL;
    } else {
	static struct linger l = { 1, LINGER_TIME };
	if (domain == sock_global_domain) {
	    int enabled = 1;
	    if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &enabled,
			   sizeof enabled) != 0) {
		errcode = errno;
		::close(s);
		return NULL;
	    }
	}
	if (setsockopt(s, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof l) != 0) {
	    errcode = invalid_access_mode;
	    ::close(s);
	    return NULL;
	}
	errcode = ok;
	return new FSocket_Posix(s);
    }
}

int
FSocket_Posix::cancel_accept()
{
    // Wakeup listener
    state = ss_shutdown;
    delete FSocket::connect(address, domain, 1, 0);
    return 1;
}


int
FSocket_Posix::connect(int max_attempts, time_t timeout)
{
    int rc;
    char *p;
    char hostname[MAX_HOST_NAME];
    unsigned short port;

    assert(address != NULL);

    if (domain != sock_local_domain) {
	if ((p = strchr(address, ':')) == NULL
	    || unsigned (p - address) >= sizeof(hostname)
	    || sscanf(p + 1, "%hd", &port) != 1) {
	    errcode = bad_address;
	    return 0;
	}
	memcpy(hostname, address, p - address);
	hostname[p - address] = '\0';
    }
    create_file = 0;

    union
    {
	sockaddr sock;
	sockaddr_in sock_inet;
	char name[MAX_HOST_NAME];
    }
    u;

    int sa_length;

    if (domain == sock_local_domain || (domain == sock_any_domain &&
					strcmp(hostname, "localhost") == 0)) {
	// connect UNIX socket
	u.sock.sa_family = AF_UNIX;

	assert(strlen(unix_socket_dir) + strlen(address)
	       < MAX_HOST_NAME - offsetof(sockaddr, sa_data));

	sa_length = offsetof(sockaddr, sa_data) +
	    sprintf(u.sock.sa_data, "%s%s", unix_socket_dir, address);
    } else {
	u.sock_inet.sin_family = AF_INET;
	u.sock_inet.sin_addr.s_addr = inet_addr(hostname);

	if ((int) (u.sock_inet.sin_addr.s_addr) == -1) {
	    struct hostent *hp;	// entry in hosts table
	    if ((hp = gethostbyname(hostname)) == NULL ||
		hp->h_addrtype != AF_INET) {
		errcode = bad_address;
		return 0;
	    }
	    memcpy(&u.sock_inet.sin_addr, hp->h_addr,
		   sizeof u.sock_inet.sin_addr);
	}
	u.sock_inet.sin_port = htons(port);
	sa_length = sizeof(u.sock_inet);
    }
    while (1) {
	if ((fd = socket(u.sock.sa_family, SOCK_STREAM, 0)) < 0) {
	    errcode = errno;
	    return 0;
	}
	do {
	    rc =::connect(fd, &u.sock, sa_length);
	} while (rc < 0 && errno == EINTR);

	if (rc < 0) {
	    errcode = errno;
	    ::close(fd);
	    if (errcode == ENOENT || errcode == ECONNREFUSED) {
		if (--max_attempts > 0) {
		    sleep(timeout);
		} else {
		    break;
		}
	    } else {
		return 0;
	    }
	} else {
	    if (u.sock_inet.sin_family == AF_INET) {
		int enabled = 1;
		if (setsockopt
		    (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &enabled,
		     sizeof enabled) != 0) {
		    errcode = errno;
		    ::close(fd);
		    return 0;
		}
	    }
	    errcode = ok;
	    state = ss_open;
	    return 1;
	}
    }
    errcode = connection_failed;
    return 0;
}

int
FSocket_Posix::read(void *buf, size_t min_size, size_t max_size,
		    time_t timeout)
{
    size_t size = 0;
    time_t start = 0;
    if (state != ss_open) {
	errcode = not_opened;
	return -1;
    }
    if (timeout != WAIT_FOREVER) {
	start = time(NULL);
    }
    do {
	ssize_t rc;
	if (timeout != WAIT_FOREVER) {
	    fd_set events;
	    struct timeval tm;
	    FD_ZERO(&events);
	    FD_SET(fd, &events);
	    tm.tv_sec = timeout;
	    tm.tv_usec = 0;
	    while ((rc = select(fd + 1, &events, NULL, NULL, &tm)) < 0
		   && errno == EINTR);
	    if (rc < 0) {
		errcode = errno;
		return -1;
	    }
	    if (rc == 0) {
		return size;
	    }
	    time_t now = time(NULL);
	    timeout = start + timeout >= now ? 0 : timeout + start - now;
	}
	while ((rc =::read(fd, (char *) buf + size, max_size - size)) < 0
	       && errno == EINTR);
	if (rc < 0) {
	    errcode = errno;
	    return -1;
	} else if (rc == 0) {
	    errcode = broken_pipe;
	    return -1;
	} else {
	    size += rc;
	}
    } while (size < min_size);

    return (int) size;
}


int
FSocket_Posix::read(void *buf, size_t size)
{
    if (state != ss_open) {
	errcode = not_opened;
	return 0;
    }

    do {
	ssize_t rc;
	while ((rc =::read(fd, buf, size)) < 0 && errno == EINTR);
	if (rc < 0) {
	    errcode = errno;
	    return 0;
	} else if (rc == 0) {
	    errcode = broken_pipe;
	    return 0;
	} else {
	    buf = (char *) buf + rc;
	    size -= rc;
	}
    } while (size != 0);

    return 1;
}


int
FSocket_Posix::write(void const *buf, size_t size)
{
    if (state != ss_open) {
	errcode = not_opened;
	return 0;
    }

    do {
	ssize_t rc;
	while ((rc =::write(fd, buf, size)) < 0 && errno == EINTR);
	if (rc < 0) {
	    errcode = errno;
	    return 0;
	} else if (rc == 0) {
	    errcode = broken_pipe;
	    return 0;
	} else {
	    buf = (char *) buf + rc;
	    size -= rc;
	}
    } while (size != 0);

    //
    // errcode is not assigned 'ok' value beacuse write function 
    // can be called in parallel with other socket operations, so
    // we want to preserve old error code here.
    //
    return 1;
}

int
FSocket_Posix::close()
{
    if (state != ss_close) {
	state = ss_close;
	if (::close(fd) == 0) {
	    errcode = ok;
	    return 1;
	} else {
	    errcode = errno;
	    return 0;
	}
    }
    errcode = ok;
    return 1;
}

int
FSocket_Posix::shutdown()
{
    if (state == ss_open) {
	state = ss_shutdown;
	int rc =::shutdown(fd, 2);
	if (rc != 0) {
	    errcode = errno;
	    return 0;
	}
    }
    return 1;
}

FSocket_Posix::~FSocket_Posix()
{
    close();
    if (create_file) {
	char name[MAX_HOST_NAME];
	sprintf(name, "%s%s", unix_socket_dir, address);
	unlink(name);
    }
    delete[]address;
}

FSocket_Posix::FSocket_Posix(const char *addr, socket_domain domain)
{
    address = strdup(addr);
    this->domain = domain;
    create_file = 0;
    errcode = ok;
}

FSocket_Posix::FSocket_Posix(int new_fd)
{
    fd = new_fd;
    address = NULL;
    create_file = 0;
    state = ss_open;
    errcode = ok;
}

FSocket *
FSocket::create_local(char const *address, int listen_queue_size)
{
    FSocket_Posix *sock = new FSocket_Posix(address, sock_local_domain);
    sock->open(listen_queue_size);
    return sock;
}

FSocket *
FSocket::create_global(char const *address, int listen_queue_size)
{
    FSocket_Posix *sock = new FSocket_Posix(address, sock_global_domain);
    sock->open(listen_queue_size);
    return sock;
}

FSocket *
FSocket::connect(char const *address,
		 socket_domain domain, int max_attempts, time_t timeout)
{
    FSocket_Posix *sock = new FSocket_Posix(address, domain);
    sock->connect(max_attempts, timeout);
    return sock;
}

char const *
get_process_name()
{
    static char name[MAX_HOST_NAME + 8];
    struct utsname local_host;
    uname(&local_host);
    sprintf(name, "%s:%d", local_host.nodename, (int) getpid());
    return name;
}

--- NEW FILE: FSocket_Posix.H ---
/* -*-C++-*- 

   "$Id: FSocket_Posix.H,v 1.1 2006-10-03 11:24:50 dslinux_amadeus Exp $"
   
   Copyright 1997 GARRET.
   Copyright 1999-2000 by the Flek development team.
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library 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
   Library General Public License for more details.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
   USA.
   
   Please report all bugs and problems to "flek-devel at sourceforge.net".

*/

// FSocket was adapted from K.A. Knizhnik's very nice SAL library.

#ifndef __FSOCKET_POSIX_H__
#define __FSOCKET_POSIX_H__

#include <Flek/FSocket.H>

class FSocket_Posix : public FSocket { 
 protected: 
  descriptor_t fd; 
  int errcode; // error code of last failed operation 
  char* address; // host address
  socket_domain domain; // Unix domain or INET socket
  int create_file; // Unix domain sockets use files for connection
  
  enum error_codes { 
    ok = 0,
    not_opened = -1,
    bad_address = -2,
    connection_failed = -3,
    broken_pipe = -4, 
    invalid_access_mode = -5
  };
  
 public: 
  //
  // Directory for Unix Domain socket files. This directory should be 
  // either empty or be terminated with "/". Dafault value is "/tmp/"
  //
  static char* unix_socket_dir; 
  
  int open(int listen_queue_size);
  int connect(int max_attempts, time_t timeout);

  int read(void* buf, size_t min_size, size_t max_size,time_t timeout);
  int read(void* buf, size_t size);
  int write(void const* buf, size_t size);

  int valid(); 
  int shutdown();
  int close();
  void get_error_text(char* buf, size_t buf_size);

  FSocket* accept();
  int cancel_accept();
    
  FSocket_Posix(const char* address, socket_domain domain); 
  FSocket_Posix(int new_fd);
  
  ~FSocket_Posix();
};

#endif

--- NEW FILE: Fl_Calendar.cxx ---
/* -*-C++-*- 

   "$Id: Fl_Calendar.cxx,v 1.1 2006-10-03 11:24:51 dslinux_amadeus Exp $"
   
   Copyright 1999-2000 by the Flek development team.
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library 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
   Library General Public License for more details.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
[...962 lines suppressed...]
    }

    prv_year->size(prv_year->w(), title_height);
    prv_year->label("Y-");

    prv_month->size(prv_month->w(), title_height);
    prv_month->label("M-");

    nxt_month->size(nxt_month->w(), title_height);
    nxt_month->label("M+");

    nxt_year->size(nxt_year->w(), title_height);
    nxt_year->label("Y+");

    caption->size(caption->w(), title_height);

    Fl_Calendar_Base::csize(x, y + title_height + (h - title_height) / 7, w,
			    h - title_height - (h - title_height) / 7);
    update();
}

--- NEW FILE: Fl_Toggle_Node_Base.cxx ---

--- NEW FILE: Flve_Input.cxx ---
//      ======================================================================
//      File:    Flve_Input.cxx - Flve_Input implementation
//      Library: flvw - FLTK Virtual widget library
//      Version: 0.1.0
//      Started: 01/12/2000
//
//      Copyright (C) 1999 Laurence Charlton
//
//      Description:
//      Flve_Input implements cell text editing for a list/table.
//      ======================================================================

#include <FL/Fl.H>
#include <Flek/Flve_Input.H>

int
Flve_Input::handle(int event)
{
    int stat = Fl_Input::handle(event);
    if (event == FL_KEYBOARD) {
	//if (stat)
	//{
	//damage(FL_DAMAGE_CHILD);
	//draw();
	//}
	if (!stat && owner) {
	    if (owner->handle(FL_SHORTCUT))
		return 1;
	}
    }
    return stat;
}

--- NEW FILE: FSGI.cxx ---
#include <Flek/math.H>
#include <Flek/FFile.H>
#include <Flek/FImage.H>
#include <Flek/FSGI.H>
#include <stdio.h>
#include <string.h>

/*
 * Reads 8 bit run length encoded data of size width from input.  
 * The read data is stored in the array row.
 */
static int
get_rle8(FFile & input, int width, uchar * row)
{
    int i;
    uchar c;
    int run_count;		// RLE runs
    int length;			// Bytes read 

    length = 0;

    while (width > 0) {
	input.get_hi(c);
	if (input.bad()) {
	    // CET - libstdc++ is evil on Linux
	    // cerr << "ERROR" << endl;
	    fprintf(stderr, "ERROR\n");
	    return -1;
	}

	length++;

	run_count = c & 127;
	if (run_count == 0)
	    break;

	if (c & 128) {
	    input.read(row, run_count);
	    length += run_count;
	    width -= run_count;
	    row += run_count;
	} else {
	    input.get_hi(c);
	    length++;
	    for (i = 0; i < run_count; i++, row++, width--)
		*row = c;
	}
    }
    return (width > 0 ? -1 : length);
}

static int
put_rle8(FFile & output, int width, uchar * row)
{
    int length;			// Byte count of output line 
    int run_count;		// Number of repeated/non-repeated pixels
    int x;
    int i;
    uchar *start, repeat;

    for (x = width, length = 0; x > 0;) {
	start = row;
	row += 2;
	x -= 2;

	while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0])) {
	    row++;
	    x--;
	}

	row -= 2;
	x += 2;

	run_count = row - start;
	while (run_count > 0) {
	    i = run_count > 126 ? 126 : run_count;
	    run_count -= i;

	    output.put_hi((uchar) (128 | i));
	    length++;

	    while (i > 0) {
		output.put_hi((uchar) * start);

		start++;
		length++;
		i--;
	    }
	}

	if (x <= 0)
	    break;

	start = row;
	repeat = row[0];

	row++;
	x--;

	while (x > 0 && *row == repeat) {
	    row++;
	    x--;
	}

	run_count = row - start;
	while (run_count > 0) {
	    i = run_count > 126 ? 126 : run_count;
	    run_count -= i;

	    output.put_hi((uchar) i);

	    output.put_hi((uchar) repeat);

	    length += 2;
	}
    }

    length++;

    output.put_hi((char) 0);
    if (output.bad())
	return -1;

    return length;
}

typedef struct
{
    int bpc;			// Bytes per channel
    int compression;		// Compression 
    ushort width,		// Width in pixels
      height,			// Height in pixels
      channels;			// Number of channels 
    ulong first_row,		// File offset for first row
      next_row,			// File offset for next row
    **table,			// Offset table for compression
    **length;			// Length table for compression 
    uchar *arle_row;		// Advanced RLE compression buffer
    long arle_offset,		// Advanced RLE buffer offset
      arle_length;		// Advanced RLE buffer length
}
sgiT;

int
sgi_put_row(FFile & output, sgiT & img, uchar * row, int y, int channel)
{
    int x;
    long offset;

    if (!row)
	return -1;

    switch (img.compression) {
    case FSGI::NONE:

	offset = 512 + (y + channel * img.height) * img.width * img.bpc;
	if (offset != output.tell())
	    output.seek(offset);

	if (img.bpc == 1)
	    output.write((char *) row, img.width);

	break;

    case FSGI::ARLE:

	// Check the last row written.
	if (img.arle_offset > 0) {
	    for (x = 0; x < img.width; x++)
		if (row[x] != img.arle_row[x])
		    break;

	    if (x == img.width) {
		img.table[channel][y] = img.arle_offset;
		img.length[channel][y] = img.arle_length;
		return (0);
	    }
	}
	// If that didn't match, search the previous rows.
	output.seek((long) img.first_row);

	if (img.bpc == 1) {
	    do {
		img.arle_offset = output.tell();
		if ((img.arle_length =
		     get_rle8(output, img.width, img.arle_row)) < 0) {
		    x = 0;
		    break;
		}

		for (x = 0; x < img.width; x++)
		    if (row[x] != img.arle_row[x])
			break;
	    }
	    while (x < img.width);
	} else {
	    // CET - libstdc++ is evil on Linux
	    //cerr << "SGI files larger than 1 byte per channel are not supported." << endl;
	    fprintf(stderr,
		    "SGI files larger than 1 byte per channel are not supported.\n");
	    return -1;
	}

	if (x == img.width) {
	    img.table[channel][y] = img.arle_offset;
	    img.length[channel][y] = img.arle_length;
	    return 0;
	} else
	    output.seek(0);

    case FSGI::RLE:

	img.table[channel][y] = img.next_row;
	offset = (long) img.next_row;

	if (offset != output.tell())
	    output.seek(offset);

	if (img.bpc == 1)
	    x = put_rle8(output, img.width, row);
	else {
	    // CET - libstdc++ is evil on Linux
	    //cerr << "SGI files larger than 1 byte per channel are not supported." << endl;
	    // CET - libstdc++ is evil on Linux
	    fprintf(stderr,
		    "SGI files larger than 1 byte per channel are not supported.\n");
	    return -1;
	}

	if (img.compression == FSGI::ARLE) {
	    img.arle_offset = offset;
	    img.arle_length = x;
	    memcpy(img.arle_row, row, img.width);
	}

	img.next_row = output.tell();
	img.length[channel][y] = x;

	return x;
    }

    return 0;
}

int
sgi_get_row(FFile & input, sgiT & img, uchar * row, int y, int channel)
{
    ulong offset;

    if ((!row) ||
	(y < 0) || (y >= img.height) ||
	(channel < 0) || (channel >= img.channels))
	return -1;

    switch (img.compression) {
    case FSGI::NONE:

	offset = 512 + (y + channel * img.height) * img.width * img.bpc;

	if (offset != (ulong) input.tell())
	    input.seek((long) offset);

	if (img.bpc == 1) {
	    input.read(row, img.width);
	    row += img.width;
	} else {
	    // CET - libstdc++ is evil on Linux
	    //cerr << "Not supported" << endl;
	    fprintf(stderr, "Not supported\n");
	    return -1;
	}
	break;

    case FSGI::RLE:
	offset = img.table[channel][y];
	if (offset != (ulong) input.tell())
	    input.seek((long) offset);
	if (input.bad()) {
	    // CET - libstdc++ is evil on Linux
	    //cerr << "ERROR: Bad seek" << endl;
	    fprintf(stderr, "ERROR: Bad seek\n");
	}
	if (input.bad()) {
	    // CET - libstdc++ is evil on Linux
	    //cerr << "ERROR: Bad seek (EOF)" << endl;
	    fprintf(stderr, "ERROR: Bad seek (EOF)\n");
	}
	if (img.bpc == 1)
	    return (get_rle8(input, img.width, row));

	// CET - libstdc++ is evil on Linux
	//cerr << "SGI files larger than 1 byte per channel are not supported." << endl;
	fprintf(stderr,
		"SGI files larger than 1 byte per channel are not supported.\n");
	return -1;
    }

    return 0;
}

#include <stdlib.h>

FImage *
FSGI::read(char *filename)
{
    FFile input;
    sgiT img;
    input.open(filename, FFileRead);
    uchar c;

    short magic;
    input.get_hi(magic);

    if (magic != MAGIC)
	return 0;

    input.get_hi(c);
    img.compression = c;
    input.get_hi(c);
    img.bpc = c;
    input.get_hi(img.width);	// Dimensions (ignore)
    input.get_hi(img.width);
    input.get_hi(img.height);
    input.get_hi(img.channels);
    unsigned long t;
    input.get_hi(t);		// Minimum pixel 
    input.get_hi(t);		// Maximum pixel 

    FImage *Nimg = new FImage(img.width, img.height, 4);

    if (img.compression) {
	int i, j;

	input.seek(512);

	if (input.bad()) {
	    // CET - libstdc++ is evil on Linux
	    //cerr << "ERROR @sgiReadFile." << endl;
	    fprintf(stderr, "ERROR @sgiReadFile.\n");
	}
	img.table = new ulongPtr[img.channels];
	img.table[0] = new ulong[img.height * img.channels];

	for (i = 1; i < img.channels; i++)
	    img.table[i] = img.table[0] + i * img.height;

	for (i = 0; i < img.channels; i++)
	    for (j = 0; j < img.height; j++) {
		ulong offset;
		input.get_hi(offset);
		img.table[i][j] = offset;
	    }
    }

    uchar *pixel = *(Nimg->begin());

    // Allocate enough memory for one line of the image.
    uchar **rows = new ucharPtr[img.channels];
    rows[0] = new uchar[img.width * img.channels];
    for (int z = 0; z < img.channels; z++)
	rows[z] = rows[0] + z * img.width;

    if (img.channels == 4) {
	for (int y = 0; y < img.height; y++) {
	    sgi_get_row(input, img, rows[0], y, 0);
	    sgi_get_row(input, img, rows[1], y, 1);
	    sgi_get_row(input, img, rows[2], y, 2);
	    sgi_get_row(input, img, rows[3], y, 3);

	    for (int x = 0; x < img.width; x++, pixel += 4) {
		pixel[0] = rows[0][x];
		pixel[1] = rows[1][x];
		pixel[2] = rows[2][x];
		pixel[3] = rows[3][x];
	    }
	}
    } else if (img.channels == 3) {
	for (int y = 0; y < img.height; y++) {
	    sgi_get_row(input, img, rows[0], y, 0);
	    sgi_get_row(input, img, rows[1], y, 1);
	    sgi_get_row(input, img, rows[2], y, 2);

	    for (int x = 0; x < img.width; x++, pixel += 4) {
		pixel[0] = rows[0][x];
		pixel[1] = rows[1][x];
		pixel[2] = rows[2][x];
		pixel[3] = 255;
	    }
	}
    } else if (img.channels == 2) {
	for (int y = 0; y < img.height; y++) {
	    sgi_get_row(input, img, rows[0], y, 0);
	    sgi_get_row(input, img, rows[1], y, 1);

	    for (int x = 0; x < img.width; x++, pixel += 4) {
		pixel[0] = rows[0][x];
		pixel[1] = rows[1][x];
		pixel[2] = 0;
		pixel[3] = 255;
	    }
	}
    } else if (img.channels == 1)	// Gray
    {
	for (int y = 0; y < img.height; y++) {
	    sgi_get_row(input, img, rows[0], y, 0);

	    for (int x = 0; x < img.width; x++, pixel += 4) {
		pixel[0] = pixel[1] = pixel[2] = rows[0][x];
		pixel[3] = 255;
	    }
	}
    }

    if (img.compression) {
	delete img.table[0];
	img.table[0] = 0;
	delete[]img.table;
    }
    delete[]rows[0];
    delete[]rows;

    return Nimg;
}

#include <string.h>

int
FSGI::write(char *filename, FImage * data, int compression, int channels)
{
    FFile output;
    output.open(filename, FFileWritePlus);

    sgiT img;
    uchar c;
    int i;

    img.bpc = 1;
    img.compression = compression;
    img.width = data->width();
    img.height = data->height();
    img.channels = channels;
    img.first_row = 0;
    img.next_row = 0;
    img.table = 0;
    img.length = 0;
    img.arle_row = 0;
    img.arle_offset = 0;
    img.arle_length = 0;

    output.put_hi((unsigned short) MAGIC);
    c = (img.compression != 0);
    output.put_hi(c);		// compression
    c = img.bpc;
    output.put_hi(c);		// bpc
    output.put_hi((unsigned short) 3);	// dimensions
    output.put_hi(img.width);
    output.put_hi(img.height);
    output.put_hi(img.channels);
    output.put_hi((long) 0);	// Minimum pixel 
    output.put_hi((long) 255);	// Maximum pixel 
    output.put_hi((long) 0);	// Reserved

    // This bit helps stop us from wasting processor time on blank space.
    int blankSize =
	max((unsigned short)
	    max((unsigned short) 488,
		(unsigned short) (img.width * img.channels)),
	    (unsigned short) (img.height * img.channels * 4));
    char *blank = new char[blankSize];
    memset(blank, 0, blankSize);

    output.write(blank, 488);	// 80+102*4 = 488

    switch (compression) {
    case FSGI::NONE:

	for (i = img.height; i > 0; i--)
	    output.write(blank, img.width * img.channels);

	break;

    case FSGI::ARLE:

	// Allocate an extra row for ARLE
	img.arle_row = new uchar[img.width];
	img.arle_offset = 0;

    case FSGI::RLE:

	// Write blank scanline tables for RLE and ARLE
	// Write 0s for img.height * img.channels * 2 * sizeof (long)
	output.write(blank, img.height * sizeof(long) * img.channels);
	output.write(blank, img.height * sizeof(long) * img.channels);

	img.first_row = output.tell();
	img.next_row = output.tell();

	img.table = new ulongPtr[img.channels];
	img.table[0] = new ulong[img.height * img.channels];

	img.length = new ulongPtr[img.channels];
	img.length[0] = new ulong[img.height * img.channels];

	for (i = 1; i < img.channels; i++) {
	    img.table[i] = img.table[0] + (i * img.height);
	    img.length[i] = img.length[0] + (i * img.height);
	}

	break;
    }

    uchar *pixel;

    uchar **rows = new ucharPtr[img.channels];
    rows[0] = new uchar[img.width * img.channels];

    for (int z = 1; z < img.channels; z++)
	rows[z] = rows[0] + z * img.width;

    pixel = *(data->begin());

    if (img.channels == 4) {
	for (int y = 0; y < img.height; y++) {
	    for (int x = 0; x < img.width; x++, pixel += 4) {
		rows[0][x] = pixel[0];
		rows[1][x] = pixel[1];
		rows[2][x] = pixel[2];
		rows[3][x] = pixel[3];
	    }

	    sgi_put_row(output, img, rows[0], y, 0);
	    sgi_put_row(output, img, rows[1], y, 1);
	    sgi_put_row(output, img, rows[2], y, 2);
	    sgi_put_row(output, img, rows[3], y, 3);
	}
    } else if (img.channels == 3) {
	for (int y = 0; y < img.height; y++) {
	    for (int x = 0; x < img.width; x++, pixel += 4) {
		rows[0][x] = pixel[0];
		rows[1][x] = pixel[1];
		rows[2][x] = pixel[2];
	    }

	    sgi_put_row(output, img, rows[0], y, 0);
	    sgi_put_row(output, img, rows[1], y, 1);
	    sgi_put_row(output, img, rows[2], y, 2);
	}
    } else if (img.channels == 2) {
	for (int y = 0; y < img.height; y++) {
	    for (int x = 0; x < img.width; x++, pixel += 4) {
		rows[0][x] = pixel[0];
		rows[1][x] = pixel[1];
	    }

	    sgi_put_row(output, img, rows[0], y, 0);
	    sgi_put_row(output, img, rows[1], y, 1);
	}
    } else if (img.channels == 1) {
	for (int y = 0; y < img.height; y++) {
	    for (int x = 0; x < img.width; x++, pixel += 4) {
		rows[0][x] = pixel[0];
	    }

	    sgi_put_row(output, img, rows[0], y, 0);
	}
    }

    if (img.compression != NONE) {
	output.seek(512);

	// Write the offset table.
	lo_to_hi(img.table[0], img.channels * img.height);
	output.write((char *) img.table[0], img.height * img.channels * 4);

	// Write the length table.
	lo_to_hi(img.length[0], img.channels * img.height);
	output.write((char *) img.length[0], img.height * img.channels * 4);

    }

    output.close();

    if (compression == FSGI::ARLE)
	delete[]img.arle_row;

    if (compression) {
	delete[]img.table[0];
	delete[]img.table;
	delete[]img.length[0];
	delete[]img.length;
    }

    delete[]rows[0];
    delete[]rows;
    delete[]blank;
    return 0;
}

bool
FSGI::valid(char *filename)
{
    FFile input;
    input.open(filename, FFileRead);

    short magic;
    input.get_hi(magic);

    input.close();

    if (magic != MAGIC)
	return false;

    return true;
}

--- NEW FILE: Flve_Combo.cxx ---
//      ======================================================================
//      File:    Flve_Combo.cxx - Flve_Combo implementation
//      Library: flvw - FLTK Virtual widget library
//      Version: 0.1.0
//      Started: 01/12/2000
//
//      Copyright (C) 1999 Laurence Charlton
//
//      Description:
//      Flve_Combo implements combo box functionality
//      Included are select from list, text with list, incremental search
//      ======================================================================

#include <FL/Fl.H>
#include <Flek/Flve_Combo.H>
#include <FL/fl_draw.H>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#if FL_MAJOR_VERSION == 1
#define text_color() FL_BLACK
#define text_font() FL_HELVETICA
#define text_size() 12
#define fl_contrast(x,y) FL_BLACK
#define selection_text_color() FL_WHITE
#define FL_DAMAGE_HIGHLIGHT FL_DAMAGE_CHILD
#define label_font labelfont
#define label_size labelsize
#define label_color labelcolor
#define label_type labeltype
#endif

#define ADDSIZE 10
#define BUTTON_WIDTH 17

#ifdef WIN32
#define STRCASECMP  stricmp
#define STRNCASECMP strncmpi
#else
#define STRCASECMP  strcasecmp
#define STRNCASECMP strncasecmp
#endif

char *
get_value(int R)
{
    static char buf[20];
    sprintf(buf, "%d", R);
    return buf;
}

class Flvl_Drop:public Flv_List
{
  public:
    int last_row;
      Flvl_Drop(int x, int y, int w, int h, const char *l =
		0):Flv_List(x, y, w, h, l)
    {
	combo = 0;
	last_row = -1;
    };
    Flve_Combo *combo;
  protected:
    void draw_row(int Offset, int &X, int &Y, int &W, int &H, int R);
};

class Flvw_Drop:public Fl_Window
{
  public:
    int key;
    Flvl_Drop *drop_list;
    Flve_Combo *combo;
    Fl_Widget *pushed;

      Flvw_Drop(int w, int h, const char *l = 0);
     ~Flvw_Drop();
  protected:
    int handle(int event);
};

class Flvt_Input:public Fl_Input
{
  public:
    Flvt_Input(int x, int y, int w, int h, const char *l =
	       0):Fl_Input(x, y, w, h, l)
    {
    };
  protected:
    int handle(int event);
    void draw(void);
};

Flvw_Drop::Flvw_Drop(int w, int h, const char *l):
Fl_Window(w, h, l)
{
    drop_list = new Flvl_Drop(0, 0, w, h);
    ((Flvl_Drop *) drop_list)->has_scrollbar(FLVS_VERTICAL);
    pushed = 0;
}

Flvw_Drop::~Flvw_Drop()
{
    if (drop_list)
	delete drop_list;
}

int
Flvw_Drop::handle(int event)
{
    int ex, ey, stat, r;

    ex = Fl::event_x();
    ey = Fl::event_y();
    r = drop_list->row();
    switch (event) {
    case FL_PUSH:
	if (ex < 0 || ex > w() || ey < 0 || ey > h()) {
	    key = 0;
	    hide();
	    return 1;
	}
	break;
    case FL_KEYBOARD:
	stat = Fl::event_key();
	if (Fl::event_ctrl())
	    stat = flv_ctrl(stat);
	if (Fl::event_alt())
	    stat = flv_alt(stat);
	if (Fl::event_shift())
	    stat = flv_shift(stat);
	if (stat == combo->drop_key()) {
	    key = 0;
	    hide();
	    return 1;
	}
	switch (Fl::event_key()) {
	    // modified behavior of escape key to restore original value
	    // of the input widget.
	    // TAB and Enter both accept the new value
	    // D.Freese (dfreese at intrepid.net)
	case FL_Escape:
	    key = 0;
	    hide();
	    return 1;
	case FL_Enter:
	case FL_Tab:
	    combo->item.index(drop_list->row());
	    key = Fl::event_key();
	    //if (key==FL_Escape)
	    //      key = 0;
	    hide();
	    return 1;
	}
	break;
    }
    if (pushed && (event == FL_DRAG || event == FL_RELEASE) &&
	contains(pushed) && pushed != this)
	stat = pushed->handle(event);
    else
	stat = ((Fl_Widget *) drop_list)->handle(event);

    if (!stat && event == FL_KEYBOARD)
	stat = ((Fl_Widget *) combo)->handle(event);

    pushed = Fl::pushed();
    if (event == FL_PUSH && r == drop_list->row() && pushed == this) {
	combo->item.index(drop_list->row());
	key = 0;
	hide();
	return 1;
    }
    return stat;
}

void
Flvl_Drop::draw_row(int Offset, int &X, int &Y, int &W, int &H, int R)
{
    Flv_Style s;

    get_style(s, R);
    Flv_List::draw_row(Offset, X, Y, W, H, R);
    fl_draw(combo->item[R].item(), X - Offset, Y, W, H, s.align());
    if (last_row != row()) {
	combo->value(combo->item[row()].item());
	last_row = row();
    }
}

void
Flvt_Input::draw(void)
{

    Fl_Widget *f = Fl::focus();
    //      Kludge so that events don't get fired all over the place
    //      We just want the input to draw correctly as though it had the
    //      focus.
    if (f && f != parent())
	f = NULL;
    if (f)
	Fl::focus_ = this;
    Fl_Input::draw();
    if (f)
	Fl::focus_ = f;
}

int
Flvt_Input::handle(int event)
{
    int stat, t, i = 0;
    Flve_Combo *w;

    w = (Flve_Combo *) parent();
    if (w)
	i = w->item.index();
    switch (event) {
    case FL_FOCUS:
    case FL_UNFOCUS:
	Fl_Input::handle(event);
	return 0;
    }
    t = (position() == mark());
    stat = Fl_Input::handle(event);
    if (event != FL_KEYBOARD)
	return stat;

    switch (Fl::event_key()) {
    case FL_BackSpace:
	//        If nothing was selected, Backspace already worked
	if (t)
	    break;
	Fl_Input::handle(event);
	break;
    case FL_Pause:
    case FL_Scroll_Lock:
    case FL_Num_Lock:
    case FL_Caps_Lock:
    case FL_Shift_L:
    case FL_Shift_R:
    case FL_Control_L:
    case FL_Control_R:
    case FL_Meta_L:
    case FL_Meta_R:
    case FL_Alt_L:
    case FL_Alt_R:
	return stat;
    }

    //printf("At this point, my value is [%s]\n", value());

    if (!w) {
#ifdef PIXIL
	Fl_Input::redraw();
#endif
	return stat;
    }
    if (!w->incremental_search()) {
#ifdef PIXIL
	Fl_Input::redraw();
#endif
	return stat;
    }

    if (w->item.findi(value()) > -1) {
	t = position();
	if (w->list) {
	    ((Flvw_Drop *) w->list)->drop_list->row(w->item.index());
	    ((Flvw_Drop *) w->list)->drop_list->last_row =
		((Flvw_Drop *) w->list)->drop_list->row();
	}
	value(w->item[w->item.index()].item());
	position(t + 1, size());

    } else if (w->list_only()) {
	t = position();
	value(w->item[i].item());
	position((t ? t - 1 : t), size());
    }
#ifdef PIXIL
    Fl_Input::redraw();
#endif
    return stat;
}

Flve_Combo::Flve_Combo(int x, int y, int w, int h, const char *l):
Fl_Widget(x, y, w, h, l)
{
    vlist_only = true;
    vincremental_search = true;
    vlist_title = 0;
    Fl_Group *gsave = Fl_Group::current();
    Fl_Group::current(0);
    input = new Flvt_Input(x, y, w, h);
    Fl_Group::current(gsave);
    box(input->box());
    input->box(FL_NO_BOX);
    resize(x, y, w, h);
    color((Fl_Color) (input->color()));
    vdisplay_rows = 8;
    vdrop_key = flv_ctrl('E');	//      Control+E
}

Flve_Combo::~Flve_Combo()
{
    if (vlist_title)
	delete vlist_title;
}

bool
Flve_Combo::list_only(bool v)
{
    if (v != vlist_only) {
	vlist_only = v;
	if (v) {
	    input->value(item[item.index()].item());
	    input->position(0, input->size());
	    input->set_changed();
	}
    }
    return vlist_only;
}

void
Flve_Combo::list_title(const char *v)
{
    if (vlist_title)
	delete vlist_title;
    vlist_title = 0;
    if (v) {
	vlist_title = new char[strlen(v) + 1];
	strcpy(vlist_title, v);
    }
}

void
Flve_Combo::resize(int X, int Y, int W, int H)
{
    Fl_Widget::resize(X, Y, W, H);
    X += (Fl::box_dx(box()));
    Y += (Fl::box_dy(box()));
    W -= (Fl::box_dw(box()));
    H -= (Fl::box_dh(box()));
    W -= BUTTON_WIDTH;

    input->resize(X, Y, W, H);
}

int
Flve_Combo::handle(int event)
{
    int stat, ex, ey, X, Y, W, H;
    Fl_Widget *wid;

    switch (event) {
    case FL_UNFOCUS:
	if (Fl::focus() == input)
	    take_focus();
	redraw();
    case FL_FOCUS:
	input->handle(event);
//                      input->position(0, input->size() );
	return 1;

    case FL_KEYBOARD:
	X = Fl::event_key();
	if (Fl::event_ctrl())
	    X = flv_ctrl(X);
	if (Fl::event_alt())
	    X = flv_alt(X);
	if (Fl::event_shift())
	    X = flv_shift(X);
	if (X == vdrop_key) {
	    open_list();
	    return 1;
	}
#ifdef PIXIL
	//      Kludge to make input think it's focused
	wid = Fl::focus_;
	Fl::focus_ = input;
	stat = input->handle(event);
	input->redraw();

	Fl::focus_ = wid;
#endif

	//      Shouldn't be doing searching if the value couldn't have changed!

	break;

    case FL_PUSH:
	//      Test for button push
	ex = Fl::event_x();
	ey = Fl::event_y();
	X = x() + w() - BUTTON_WIDTH;
	Y = y();
	W = BUTTON_WIDTH;
	H = h();
	if (ex >= X && ex < X + W && ey >= Y && ey <= Y + H) {
	    open_list();
	    return 1;
	}
	return input->handle(event);
    default:
	wid = Fl::focus_;
	Fl::focus_ = input;
	stat = input->handle(event);
	Fl::focus_ = wid;
    }
    return stat;
}

void
Flve_Combo::draw(void)
{

    int X, Y, W, H, bx;

    // modified to allow a zero length string string in input widget
    //  if input widget is modifiable

    if (list_only() == true)
	if (*(input->value()) == 0)
	    input->value(item[item.index()].item());

    if ((damage() & FL_DAMAGE_ALL) != 0)
	draw_box();

    X = x() + (Fl::box_dx(box()));
    Y = y() + (Fl::box_dy(box()));
    W = w() - (Fl::box_dw(box()));
    H = h() - (Fl::box_dh(box()));

    bx = X + W - BUTTON_WIDTH;

#if FL_MAJOR_VERSION == 2
    FL_UP_BOX->draw(bx + 1, Y, BUTTON_WIDTH, H,
		    (Fl_Color) (FL_GRAY_RAMP + 17));
#else
    draw_box(FL_UP_BOX, bx + 1, Y, BUTTON_WIDTH, H,
	     (Fl_Color) (FL_GRAY_RAMP + 17));
#endif
    fl_draw_symbol("@#2>", bx + 3, Y, BUTTON_WIDTH - 5, H, FL_BLACK);
    fl_color((Fl_Color) (FL_GRAY_RAMP + 17));
    fl_yxline(bx, Y, Y + H);
    input->draw();
}

void
Flve_Combo::open_list()
{
    int W, H, r;
    Fl_Window *win;
    Flvw_Drop *lst;

    fl_font(text_font(), text_size());
    fl_measure("X", W, H);

    r = item.count();
    if (vlist_title)
	r++;
    if (r > display_rows())
	r = display_rows();
    list = lst = new Flvw_Drop(w(), H * r + 4 + (vlist_title ? 4 : 0));
    list->box(FL_DOWN_BOX);
    list->end();

    // This is a horrible hack .. This should have a parent of the root to allow
    // it to pop up over the application window, instead of being contained
    // within it. However, the screentop and window managers pick up this window
    // and do Bad Things (TM) with it. Therefore, I've made the temporary change 
    // to make this a child of the application, and thus, it may look weird.

    // This need's fixed.

    // -Anonymous (anon at fixthisyourself.net)

    list->parent(parent());
    //      list->parent(NULL);
    lst->drop_list->rows(item.count());
    if (vlist_title)
	lst->drop_list->label(vlist_title);
    list->clear_border();
    list->set_modal();
    lst->drop_list->combo = this;
    lst->combo = this;

    // highlight the present contents of the input widget
    // if input contains a value and it can be found in the list
    // added by Dave Freese (dfreese at intrepid.net)

    if (item.findi(input->value()) > -1)
	lst->drop_list->row(item.index());
    else
	lst->drop_list->row(0);
    lst->drop_list->last_row = lst->drop_list->row();

    // end hightlight code

    win = window();
    int nx = win->x();
    int ny = win->y();

    while (win && win->parent()) {
	win = win->window();
	nx += win->x();
	ny += win->y();
    }
    if (win)
	list->position(nx + x(), ny + y() + h() - 3);

    Fl::grab(list);
    list->show();
    while (list->shown())
	Fl::wait();
    Fl::release();
    take_focus();
    // ****
//  if (((Flvw_Drop *)list)->key)
    value(item[item.index()].item());
    do_callback();

    if (win && ((Flvw_Drop *) list)->key)
	Fl::handle(FL_KEYBOARD, win);

    delete list;
    list = 0;
}

const char *
Flve_Combo::value()
{
    return input->value();
}

void
Flve_Combo::value(const char *v)
{
    input->value(v);
    input->set_changed();
    input->mark(256);
//      input->position(0, input->size() );
}

void
Flve_Combo::display_rows(int v)
{
    vdisplay_rows = v;
}

//      =================================================================
//      Flv_Combo_Item
//      =================================================================
Flv_Combo_Item::Flv_Combo_Item()
{
    vitem = 0;
    vvalue = 0;
}

Flv_Combo_Item::~Flv_Combo_Item()
{
    if (vitem)
	delete vitem;
}

const char *
Flv_Combo_Item::item(void)
{
    return (vitem ? vitem : "");
}

void
Flv_Combo_Item::item(const char *v)
{
    if (vitem)
	delete vitem;
    vitem = 0;
    if (v) {
	vitem = new char[strlen(v) + 1];
	strcpy(vitem, v);
    }
}

long
Flv_Combo_Item::value(void)
{
    return vvalue;
}

void
Flv_Combo_Item::value(long v)
{
    vvalue = v;
}

//      =================================================================
//      Flv_Combo_Items
//      =================================================================

Flv_Combo_Items::Flv_Combo_Items()
{
    list = 0;
    vcount = 0;
    vallocated = 0;
    vcurrent = 0;
    nodups = true;
}

Flv_Combo_Items::~Flv_Combo_Items()
{
    clear();
}

void
Flv_Combo_Items::add(const char *item, long v)
{
    Flv_Combo_Item *i;

    if (vcount == vallocated)
	make_room_for(vallocated + 10);
    if (vcount == vallocated)
	return;
    if (strlen(item) == 0)
	return;
    if (nodups)
	if (find(item) != -1)
	    return;

    i = new Flv_Combo_Item();
    i->item(item);
    i->value(v);
    list[vcount++] = i;
}

void
Flv_Combo_Items::insert(int index, const char *item, long v)
{
    int t;
    Flv_Combo_Item *i;

    if (vcount == vallocated)
	make_room_for(vallocated + 10);
    if (vcount == vallocated)
	return;
    if (strlen(item) == 0)
	return;
    if (nodups)
	if (find(item) != -1)
	    return;

    i = new Flv_Combo_Item();
    i->item(item);
    i->value(v);

    if (index < 0)
	index = 0;
    if (index > vcount)
	index = vcount;
    for (t = vcount; t > index; t--)
	list[t] = list[t - 1];
    list[index] = i;
    vcount++;
}

void
Flv_Combo_Items::remove(int index)
{
    int t;

    if (index < 0 || index >= vcount)
	return;
    if (list[index])
	delete list[index];
    for (t = index; t < vcount - 1; t++)
	list[t] = list[t + 1];
    list[t] = 0;
    vcount--;
    if (vcurrent >= vcount && vcurrent)
	vcurrent--;
}

void
Flv_Combo_Items::change(int i, const char *item, long v)
{
    if (i < 0 || i > vcount)
	return;
    list[i]->item(item);
    list[i]->value(v);
}

void
Flv_Combo_Items::change(int i, const char *item)
{
    if (i < 0 || i > vcount)
	return;
    list[i]->item(item);
}

void
Flv_Combo_Items::change(int i, long v)
{
    if (i < 0 || i > vcount)
	return;
    list[i]->value(v);
}

#define C(x) ((Flv_Combo_Item *)(x))

static int
cmp(const void *a, const void *b)
{
    Flv_Combo_Item *ai = *((Flv_Combo_Item **) (a)),
	*bi = *((Flv_Combo_Item **) (b));
    const char *a_item = ai->item(), *b_item = bi->item();
    long a_value = ai->value(), b_value = bi->value();

    int status = STRCASECMP(a_item, b_item);
    if (status)
	return status;
    return (a_value - b_value);
}

void
Flv_Combo_Items::sort(void)	//      Sort list
{
    if (list && vcount > 1)
	qsort(list, vcount, sizeof(Flv_Combo_Item *), cmp);
}

void
Flv_Combo_Items::clear(void)	//      Clear list
{
    int t;
    for (t = 0; t < vcount; t++)
	if (list[t])
	    delete list[t];
    if (list)
	delete[]list;
    list = 0;
    vallocated = 0;
    vcount = 0;
    vcurrent = 0;
}

void
Flv_Combo_Items::index(int i)	//      Set current index
{
    if (i < 0 || i >= vcount)
	return;
    vcurrent = i;
}

int
Flv_Combo_Items::findi(const char *v)	//      Find text return index (-1 not found)
{
    int t;
    // added for case where v is zero length
    if (*v == 0)
	return -1;
    for (t = 0; t < vcount; t++) {
	if (STRNCASECMP(list[t]->item(), v, strlen(v)) == 0) {
	    vcurrent = t;
	    return t;
	}
    }
    return -1;
}

int
Flv_Combo_Items::find(const char *v)	//      Find text return index (-1 not found)
{
    int t;
    // added for case where v is zero length
    if (*v == 0)
	return -1;
    for (t = 0; t < vcount; t++) {
	if (STRCASECMP(list[t]->item(), v) == 0) {
	    vcurrent = t;
	    return t;
	}
    }
    return -1;
}

int
Flv_Combo_Items::find(long v)	//      Find value return index (-1 not found)
{
    int t;
    for (t = 0; t < vcount; t++) {
	if (list[t]->value() == v) {
	    vcurrent = t;
	    return t;
	}
    }
    return -1;
}


Flv_Combo_Item *
Flv_Combo_Items::current(void)
{
    if (list)
	return list[vcurrent];
    return NULL;
}

Flv_Combo_Item & Flv_Combo_Items::operator[](int index) {
    static Flv_Combo_Item
	x;
    if (index < 0 || index >= vcount)
	return x;
    return *(list[index]);
}

void
Flv_Combo_Items::make_room_for(int n)
{
    if (n >= vallocated) {
	Flv_Combo_Item **a = new Flv_Combo_Item *[n];
	if (!a)
	    return;
	//      Wasted CPU cycles, but list is pretty
	memset(a, 0, sizeof(Flv_Style *) * (vallocated + ADDSIZE));
	if (vcount)
	    memcpy(a, list, sizeof(Flv_Combo_Item *) * vcount);
	vallocated += ADDSIZE;
	if (list)
	    delete[]list;
	list = a;
    }
}

--- NEW FILE: FDate.cxx ---
#include <time.h>
// Evil #include <iostream.h>
#include <iomanip.h>
#include <stdio.h>
#include <string.h>
#include <Flek/FDate.H>

// This class is based on the date class by Dave Freese
// <dfreese at intrepid.net>

const int
    FDate::days[] = {
	0,
	31,
	28,
	31,
	30,
	31,
	30,
	31,
	31,
	30,
	31,
	30,
31 };

const int
    FDate::julian_days[2][13] = {
    {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
    {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
};

const char *
    FDate::month_name[] = {
    "January",
    "Febuary",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December"
};

void
FDate::today()
{
    time_t t;
    struct tm *now;
    time(&t);
    now = localtime(&t);
    Year = now->tm_year + 1900;
    Month = now->tm_mon + 1;
    Day = now->tm_mday;
}

FDate::FDate()
{
    today();
    Fmt = 0;
}

FDate::FDate(const FDate & dt):
FBase(dt)
{
    set_date(dt);
}

FDate::FDate(int y, int m, int d)
{
    set_date(y, m, d);
    Fmt = 0;
}

FBase::Ptr FDate::copy(void) const
{
    return new FDate(*this);
}

void
FDate::set_date(int y, int m, int d)
{
    if (valid(y, m, d)) {
	Year = y;
	Month = m;
	Day = d;
    } else
	today();
}

void
FDate::set_date(const FDate & dt)
{
    Year = dt.Year;
    Month = dt.Month;
    Day = dt.Day;
    Fmt = dt.Fmt;
}

void
FDate::set_format(int iFmt)
{
    Fmt = iFmt;
}

void
FDate::year(int y)
{
    Year = y;
}

int
FDate::year()
{
    return Year;
}

void
FDate::month(int m)
{
    Month = m;
}

int
FDate::month()
{
    return Month;
}

void
FDate::day(int d)
{
    Day = d;
}

int
FDate::day()
{
    return Day;
}

bool
FDate::leap_year(int y)
{
    if (y % 400 == 0 || (y % 100 != 0 && y % 4 == 0))
	return true;
    return false;
}

bool
FDate::valid(int y, int m, int d)
{
    if (y < 1970 || y > 2035)
	return false;
    if (m < 1 || m > 12)
	return false;
    if (d < 1)
	return false;
    if (leap_year(y)) {
	if ((m == 2) && (d > 29))
	    return false;
	else
	    return true;
    }
    if (d > days[m])
	return false;
    return true;
}

/* Always link all apps with with libstdc++ for a trivial thing
   like this?  This should probably be put in a separate flek-stdc++
   library?
ostream &operator<< (ostream &output, const FDate &d) {
  output << d.to_string ();
  return output;
}
*/

bool
FDate::end_of_month(int d)
{
    if (Month == 2 && leap_year(Year))
	return (d == 29);	// last day of Feb in leap year
    else
	return (d == days[Month]);
}

void
FDate::help_increment()
{
    if (end_of_month(Day) && Month == 12) {	// end year
	Day = 1;
	Month = 1;
	++Year;
    } else if (end_of_month(Day)) {
	Day = 1;
	++Month;
    } else
	++Day;
}

FDate & FDate::operator++()
{
    help_increment();
    return *this;		// reference return to create an lvalue
}

FDate
FDate::operator++(int)
{
    FDate temp = *this;
    help_increment();
    return temp;		// return non-increment, saved temporary object
}

const FDate &
FDate::operator+=(int ndays)
{
    for (int i = 0; i < ndays; i++)
	help_increment();
    return *this;		// enables cascading
}

bool
FDate::operator==(const FDate & d)
{
    if (this->Year != d.Year)
	return false;
    if (this->Month != d.Month)
	return false;
    if (this->Day != d.Day)
	return false;
    return true;
}

bool
FDate::operator!=(const FDate & d)
{
    return (!(*this == d));
}

bool
FDate::operator<(const FDate & d)
{
    if (this->Year < d.Year)
	return true;
    if (this->Year > d.Year)
	return false;
    if (this->Month < d.Month)
	return true;
    if (this->Month > d.Month)
	return false;
    if (this->Day < d.Day)
	return true;
    return false;
}

bool
FDate::operator>(const FDate & d)
{
    if (*this < d)
	return false;
    if (*this == d)
	return false;
    return true;
}

void
FDate::operator=(const FDate & d)
{
    this->Year = d.Year;
    this->Month = d.Month;
    this->Day = d.Day;
}

double
FDate::julian_date()
{
    int days_in_year = 365;
    if (leap_year())
	days_in_year++;
    return (Year + 1.0 * (day_of_year(Year, Month, Day) - 1) / days_in_year);
}

void
FDate::next_month()
{
    if (Month == 12) {
	Month = 1;
	Year++;
    } else
	Month++;

    while ((Day >= 1) && (!valid()))
	Day--;
}

void
FDate::previous_month()
{
    if (Month == 1) {
	Month = 12;
	Year--;
    } else
	Month--;

    while ((Day >= 1) && (!valid()))
	Day--;
}

void
FDate::previous_year()
{
    if (Month == 2 && Day == 29)
	Day = 28;
    Year--;
}

void
FDate::next_year()
{
    if (Month == 2 && Day == 29)
	Day = 28;
    Year++;
}


char *
FDate::to_string(int fmt) const
{
    static char temp[20];
    char temp_month[10];
    switch (fmt) {
    case 1:
	sprintf(temp, "%02d/%02d/%04d", Month, Day, Year);
	break;
    case 2:
	sprintf(temp, "%s %2d, %4d", month_name[Month - 1], Day, Year);
	break;
    case 3:
	strcpy(temp_month, month_name[Month - 1]);
	temp_month[3] = 0;
	sprintf(temp, "%s %2d, %4d", temp_month, Day, Year);
	break;
    case 4:
	strcpy(temp_month, month_name[Month - 1]);
	temp_month[3] = 0;
	sprintf(temp, "%d %s %4d", Day, temp_month, Year);
	break;
    case 0:
    default:
	sprintf(temp, "%02d/%02d/%02d", Month, Day,
		Year > 1999 ? Year - 2000 : Year - 1900);
	break;
    }
    return temp;
}

char *
FDate::to_string() const
{
    return to_string(Fmt);
}

int
FDate::days_in_month(int month, int leap)
{
    /* Validate the month. */
    if (month < JANUARY || month > DECEMBER)
	return -1;

    /* Return 28, 29, 30, or 31 based on month/leap. */
    switch (month) {
    case FEBRUARY:
	return leap ? 29 : 28;
    default:
	return days[month];
    }
}

int
FDate::day_of_year(int year, int mon, int mday)
{
    /* Return day of year. */
    return mday + julian_days[leap_year(year) ? 1 : 0][mon];
}

int
FDate::day_of_epoch(int year, int mon, int mday)
{
    int doe;
    int era, cent, quad, rest;

    /* break down the year into 400, 100, 4, and 1 year multiples */
    rest = year - 1;
    quad = rest / 4;
    rest %= 4;
    cent = quad / 25;
    quad %= 25;
    era = cent / 4;
    cent %= 4;

    /* set up doe */
    doe = day_of_year(year, mon, mday);
    doe += era * (400 * 365 + 97);
    doe += cent * (100 * 365 + 24);
    doe += quad * (4 * 365 + 1);
    doe += rest * 365;

    return doe;
}

int
FDate::day_of_week(int year, int mon, int mday)
{
    return day_of_epoch(year, mon, mday) % 7;
}

--- NEW FILE: Flv_Style.cxx ---
//      ======================================================================
//      File:    Flv_Style.cxx - Flv_Style implementation
//      Program: Flv_Style - FLTK Virtual List/Table Styles Widget
//      Version: 0.1.0
//      Started: 11/21/99
//
//      Copyright (C) 1999 Laurence Charlton
//
//      Description:
//      The styles classes are basically defined to make life easier while
//      working with styles for the virtual classes.
//      ======================================================================

#include <FL/Fl_Widget.H>
#include <Flek/Flv_Style.H>
#include <stdio.h>
#ifdef WIN32
#include <mem.h>
#else
#include <memory.h>
#include <string.h>
#endif

#define ADDSIZE 10

//      Flv_Style bits
#define STYLE_DEFINE_FONT						0x0001
#define STYLE_DEFINE_FONT_SIZE			0x0002
#define STYLE_DEFINE_FOREGROUND			0x0004
#define STYLE_DEFINE_BACKGROUND			0x0008
#define STYLE_DEFINE_ALIGN					0x0010
#define STYLE_DEFINE_FRAME					0x0020
#define STYLE_DEFINE_RESIZABLE			0x0040
#define STYLE_DEFINE_HEIGHT					0x0080
#define STYLE_DEFINE_WIDTH					0x0100
#define STYLE_DEFINE_LOCKED					0x0200
#define STYLE_DEFINE_BORDER					0x0400
#define STYLE_DEFINE_BORDER_COLOR		0x0800
#define STYLE_DEFINE_BORDER_SPACING	0x1000
#define STYLE_DEFINE_X_MARGIN				0x2000
#define STYLE_DEFINE_Y_MARGIN				0x4000
#define STYLE_DEFINE_EDITOR					0x8000

#define CLEAR(n) vdefined &= ~(n)
#define DEFINED(n) ((vdefined & (n))!= 0)
#define DEFINED2(v,n) ((v.vdefined & (n))!= 0)

Flv_Style::Flv_Style()
{
    vdefined = 0;
    vvalue = 0;
    //      I'm not worried about initializing the rest of the private
    //      variables since they are undefined.
}

Flv_Style::Flv_Style(int value)
{
    vdefined = 0;
    vvalue = value;
    //      I'm not worried about initializing the rest of the private
    //      variables since they are undefined.
}

//      ==================================================================
//      Set drawing alignment
const Fl_Align &
Flv_Style::align(const Fl_Align & n)
{
    valign = n;
    vdefined |= STYLE_DEFINE_ALIGN;
    return valign;
}

//      Undefine drawing alignment
void
Flv_Style::clear_align(void)
{
    CLEAR(STYLE_DEFINE_ALIGN);
}

//      Is drawing alignment defined?
bool
Flv_Style::align_defined(void) const
{
    return DEFINED(STYLE_DEFINE_ALIGN);
}

//      ==================================================================
//      Set background color
Fl_Color
Flv_Style::background(Fl_Color n)
{
    vbackground = n;
    vdefined |= STYLE_DEFINE_BACKGROUND;
    return vbackground;
}

//      Undefine background color
void
Flv_Style::clear_background(void)
{
    CLEAR(STYLE_DEFINE_BACKGROUND);
}

//      Is background defined?
bool
Flv_Style::background_defined(void) const
{
    return DEFINED(STYLE_DEFINE_BACKGROUND);
}


//      ==================================================================
//      Set border
int
Flv_Style::border(int n)
{
    vborder = (unsigned char) n;
    vdefined |= STYLE_DEFINE_BORDER;
    return vborder;
}

//      Undefine border
void
Flv_Style::clear_border(void)
{
    CLEAR(STYLE_DEFINE_BORDER);
}

//      Is border defined?
bool
Flv_Style::border_defined(void) const
{
    return DEFINED(STYLE_DEFINE_BORDER);
}

//      ==================================================================
//      Set border_color
Fl_Color
Flv_Style::border_color(Fl_Color n)
{
    vborder_color = n;
    vdefined |= STYLE_DEFINE_BORDER_COLOR;
    return vborder_color;
}

//      Undefine border_color
void
Flv_Style::clear_border_color(void)
{
    CLEAR(STYLE_DEFINE_BORDER_COLOR);
}

//      Is border_color defined?
bool
Flv_Style::border_color_defined(void) const
{
    return DEFINED(STYLE_DEFINE_BORDER_COLOR);
}


//      ==================================================================
//      Set border_spacing
int
Flv_Style::border_spacing(int n)
{
    vborder_spacing = (unsigned char) n;
    vdefined |= STYLE_DEFINE_BORDER_SPACING;
    return vborder_spacing;
}

//      Undefine border_spacing
void
Flv_Style::clear_border_spacing(void)
{
    CLEAR(STYLE_DEFINE_BORDER_SPACING);
}

//      Is border_spacing defined?
bool
Flv_Style::border_spacing_defined(void) const
{
    return DEFINED(STYLE_DEFINE_BORDER_SPACING);
}

//      ==================================================================
//      Set content editor
Fl_Widget *
Flv_Style::editor(Fl_Widget * v)
{
    veditor = v;
    if (Fl::focus() != v && veditor)
	veditor->hide();
    vdefined |= STYLE_DEFINE_EDITOR;
    return veditor;
}

//      Undefine border_spacing
void
Flv_Style::clear_editor(void)
{
    CLEAR(STYLE_DEFINE_EDITOR);
}

//      Is border_spacing defined?
bool
Flv_Style::editor_defined(void) const
{
    return DEFINED(STYLE_DEFINE_EDITOR);
}

//      ==================================================================
//      Set current font
const Fl_Font &
Flv_Style::font(const Fl_Font & n)
{
    vfont = n;
    vdefined |= STYLE_DEFINE_FONT;
    return vfont;
}

//      Undefine font
void
Flv_Style::clear_font(void)
{
    CLEAR(STYLE_DEFINE_FONT);
}

//      Is font defined
bool
Flv_Style::font_defined(void) const
{
    return DEFINED(STYLE_DEFINE_FONT);
}

//      ==================================================================
//      Set font size
int
Flv_Style::font_size(int n)
{
    if (n < 1)			//      Clip at 1 as the smallest font size
	n = 1;
    vfont_size = n;
    vdefined |= STYLE_DEFINE_FONT_SIZE;
    return vfont_size;
}

//      Undefine font size
void
Flv_Style::clear_font_size(void)
{
    CLEAR(STYLE_DEFINE_FONT_SIZE);
}

//      Is font size defined?
bool
Flv_Style::font_size_defined(void) const
{
    return DEFINED(STYLE_DEFINE_FONT_SIZE);
}

//      ==================================================================
//      Set foreground color
Fl_Color
Flv_Style::foreground(Fl_Color n)
{
    vforeground = n;
    vdefined |= STYLE_DEFINE_FOREGROUND;
    return vforeground;
}

//      Undefine foreground color
void
Flv_Style::clear_foreground(void)
{
    CLEAR(STYLE_DEFINE_FOREGROUND);
}

//      Is foreground defined?
bool
Flv_Style::foreground_defined(void) const
{
    return DEFINED(STYLE_DEFINE_FOREGROUND);
}

//      ==================================================================
//      Set frame type
const Fl_Boxtype &
Flv_Style::frame(const Fl_Boxtype & n)
{
    vframe = n;
    vdefined |= STYLE_DEFINE_FRAME;
    return vframe;
}

//      Undefine frame type
void
Flv_Style::clear_frame(void)
{
    CLEAR(STYLE_DEFINE_FRAME);
}

//      Is frame type defined?
bool
Flv_Style::frame_defined(void) const
{
    return DEFINED(STYLE_DEFINE_FRAME);
}

//      ==================================================================
//      Set height
int
Flv_Style::height(int n)
{
    if (n < 0)
	n = 0;
    vdefined |= STYLE_DEFINE_HEIGHT;
    return (vheight = n);
}

//      Undefine row height
void
Flv_Style::clear_height(void)
{
    CLEAR(STYLE_DEFINE_HEIGHT);
}

//      Is row height defined?
bool
Flv_Style::height_defined(void) const
{
    return DEFINED(STYLE_DEFINE_HEIGHT);
}

//      ==================================================================
//      Set locked
bool
Flv_Style::locked(bool n)
{
    vdefined |= STYLE_DEFINE_LOCKED;
    return (vlocked = n);
}

//      Undefine locked
void
Flv_Style::clear_locked(void)
{
    CLEAR(STYLE_DEFINE_LOCKED);
}

//      Is locked defined?
bool
Flv_Style::locked_defined(void) const
{
    return DEFINED(STYLE_DEFINE_LOCKED);
}

//      ==================================================================
//      Set resizable
bool
Flv_Style::resizable(bool n)
{
    vresizable = n;
    vdefined |= STYLE_DEFINE_RESIZABLE;
    return vresizable;
}

//      Undefine resizable
void
Flv_Style::clear_resizable(void)
{
    CLEAR(STYLE_DEFINE_RESIZABLE);
}

//      Is resizable defined?
bool
Flv_Style::resizable_defined(void) const
{
    return DEFINED(STYLE_DEFINE_RESIZABLE);
}

//      ==================================================================
//      Set column width
int
Flv_Style::width(int n)
{
    if (n < 0)
	n = 0;
    vdefined |= STYLE_DEFINE_WIDTH;
    return (vwidth = n);
}

//      Undefine column width
void
Flv_Style::clear_width(void)
{
    CLEAR(STYLE_DEFINE_WIDTH);
}

//      Is column width defined?
bool
Flv_Style::width_defined(void) const
{
    return DEFINED(STYLE_DEFINE_WIDTH);
}

//      ==================================================================
//      Set x margin
int
Flv_Style::x_margin(int x)
{
    if (x < 0)
	x = 0;
    if (x != vx_margin) {
	vdefined |= STYLE_DEFINE_X_MARGIN;
	vx_margin = (unsigned char) x;
    }
    return vx_margin;
}

//      Undefine x margin
void
Flv_Style::clear_x_margin(void)
{
    CLEAR(STYLE_DEFINE_X_MARGIN);
}

//      Is x margin defined
bool
Flv_Style::x_margin_defined(void) const
{
    return DEFINED(STYLE_DEFINE_X_MARGIN);
}

//      ==================================================================
//      Set y margin
int
Flv_Style::y_margin(int y)
{
    if (y < 0)
	y = 0;
    if (y != vy_margin) {
	vdefined |= STYLE_DEFINE_Y_MARGIN;
	vy_margin = (unsigned char) y;
    }
    return vy_margin;
}

//      Undefine y margin
void
Flv_Style::clear_y_margin(void)
{
    CLEAR(STYLE_DEFINE_Y_MARGIN);
}

//      Is y margin defined
bool
Flv_Style::y_margin_defined(void) const
{
    return DEFINED(STYLE_DEFINE_Y_MARGIN);
}

//      ==================================================================
//      Cumulative assignment operator
//      This will only assign portions that are defined.
const Flv_Style &
Flv_Style::operator=(const Flv_Style & n)
{
    if (n.align_defined())
	align(n.valign);
    if (n.background_defined())
	background(n.vbackground);
    if (n.border_defined())
	border(n.vborder);
    if (n.border_color_defined())
	border_color(n.vborder_color);
    if (n.border_spacing_defined())
	border_spacing(n.vborder_spacing);
    if (n.editor_defined())
	editor(n.veditor);
    if (n.font_defined())
	font(n.vfont);
    if (n.font_size_defined())
	font_size(n.vfont_size);
    if (n.foreground_defined())
	foreground(n.vforeground);
    if (n.frame_defined())
	frame(n.vframe);
    if (n.height_defined())
	height(n.vheight);
    if (n.locked_defined())
	locked(n.vlocked);
    if (n.resizable_defined())
	resizable(n.vresizable);
    if (n.width_defined())
	width(n.vwidth);
    if (n.x_margin_defined())
	x_margin(n.vx_margin);
    if (n.y_margin_defined())
	y_margin(n.vy_margin);


    //      I'm not copying value because it seems meaningless in every context
    //      I can think of.

    //      I'm not copying cell_style either for the same reason.  It just seems like
    //      a REALLY bad idea.
    return *this;
}

//      **********************************************************************
//      Routines for Flv_Style_List
//
//      Implemented as a dynamic sparse array
//      **********************************************************************
Flv_Style_List::Flv_Style_List()
{
    list = NULL;
    vcount = vallocated = vcurrent = 0;
}

void
Flv_Style_List::compact(void)
{
    int n, t;

    //    Release memory for any dead items
    for (t = 0; t < vcount; t++) {
	list[t]->cell_style.compact();	//      Compact cells!
	if (list[t]->cell_style.count() == 0 && list[t]->all_clear()) {
	    delete list[t];
	    list[t] = NULL;
	}
    }
    //    Compact list now
    for (t = n = 0; t < vcount; t++) {
	if (list[t])
	    list[n++] = list[t];
	else if (vcurrent <= t && vcurrent > 0)
	    vcurrent--;
    }

    //    Make list easy to view, wasted CPU cycles
    for (t = n; t < vcount; t++)
	list[t] = NULL;

    vcount = n;			//      Update count

    if (!vcount && list) {
	delete[]list;
	list = NULL;
	vcount = vcurrent = vallocated = 0;
    }
}

//      Undefine all styles in list
void
Flv_Style_List::clear(void)
{
    int t;

    for (t = 0; t < vcount; t++)	//      Make all entries clear
	list[t]->clear_all();
    compact();			//      Remove dead space thats left
}

//      Free memory for all (including cell
void
Flv_Style_List::release(void)
{
    int t;
    for (t = 0; t < vcount; t++) {
	list[t]->cell_style.release();
	delete list[t];
    }
    if (list)
	delete[]list;
    list = NULL;
    vcurrent = vcount = vallocated = 0;
}

Flv_Style *
Flv_Style_List::current(void)	//      Current node
{
    if (!list)
	return NULL;
    return list[vcurrent];
}

//      Find closest match
//      It will find the first value >= n
Flv_Style *
Flv_Style_List::find(int n)
{
    int t, l, h;

    if (!list || vcount == 0)	//      If list is empty, there will be no matches
	return NULL;

    //      How a about a nice binary search?  It will be slower for sequential
    //      processing and a small number of styles, but worlds faster as the
    //      number of styles increases.  Use skip_to for sequential processing
    //      and find for random access.
    l = 0;
    h = vcount - 1;
    while (l + 1 < h) {
	vcurrent = (l + h) / 2;
	t = list[vcurrent]->value();
	if (t == n)
	    return list[vcurrent];
	else if (t < n)
	    l = vcurrent;
	else
	    h = vcurrent;
    }

    //      This needs cleaning, I fairly certain there's way too much logic here
    //      While this will work, I think we only need to check one of the values
    //      but I've been wrong before... :)
    vcurrent = l;
    t = list[vcurrent]->value();
    if (t == n)
	return list[vcurrent];
    if (t < n && vcurrent < vcount - 1) {
	vcurrent = h;
	t = list[vcurrent]->value();
	if (t == n)
	    return list[vcurrent];
    }
    return NULL;
}

Flv_Style *
Flv_Style_List::first(void)	//      Get first style
{
    if (!list)
	return NULL;
    vcurrent = 0;
    return list[vcurrent];
}

bool
Flv_Style_List::insert(Flv_Style * n)	//      Add style (if doesn't exist)
{
    int t;
    //      Make sure there is room for a new item
    if (vcount == vallocated) {
	Flv_Style **a = new Flv_Style *[vallocated + ADDSIZE];
	if (!a)
	    return false;
	//  Wasted CPU cycles, but list is pretty
	memset(a, 0, sizeof(Flv_Style *) * (vallocated + ADDSIZE));
	if (vcount)
	    memcpy(a, list, sizeof(Flv_Style *) * vcount);
	vallocated += ADDSIZE;
	if (list)
	    delete[]list;
	list = a;
    }

    if (vcount) {
	find(n->value());	//      Point to insert candidate
	if (n->value() == list[vcurrent]->value())	//      No duplicates
	    return false;
	if (n->value() > list[vcurrent]->value())	//      Insert at end of list
	    vcurrent++;
    }

    //      Make room for insert if not appending
    for (t = vcount; t > vcurrent; t--)
	list[t] = list[t - 1];

    list[vcurrent] = n;
    vcount++;
    return true;
}

Flv_Style *
Flv_Style_List::next(void)	//      Next style
{
    if (!list || vcurrent >= vcount - 1)
	return NULL;

    vcurrent++;
    return list[vcurrent];
}

Flv_Style *
Flv_Style_List::prior(void)
{

    if (!vcurrent || !list)
	return 0;
    vcurrent--;
    return list[vcurrent];
}

bool
Flv_Style_List::clear_current(void)
{
    if (!list)
	return false;

    if (list[vcurrent]->cell_style.count() == 0)
	return release_current();
    list[vcurrent]->clear_all();
    return true;
}

bool
Flv_Style_List::release_current(void)	//      Remove current style
{
    if (!list)
	return false;

    delete list[vcurrent];
    if (vcurrent < vcount - 1) {
	memmove(list + vcurrent, list + vcurrent + 1,
		sizeof(Flv_Style *) * (vcount - vcurrent));
	vcount--;
	list[vcount] = NULL;
    }
    if (vcurrent == vcount)
	vcurrent--;

    return true;
}

//      From n skip up to value v
Flv_Style *
Flv_Style_List::skip_to(int v)
{
    int c;

    if (!list || !vcount)
	return NULL;

    //      In case we're backing up or starting over
    //      We're checking vcurrent-1 so if the last search found
    //      an entry > the desired value, and this search isn't quite
    //      to the last found value, we don't want to start over, just
    //      stay where we are.
    //      Style 1, 2, 3, 7 & 10 defined
    //      search for 4 (current points to 7) returns false
    //      search for 5 (stay at seven since 3 is < value, return false)
    //              If we started at 0 we'd end up here anyway... :)
    //      search for 7 (stay at seven, we'll find it quick, return true)
    if (vcurrent) {
	if (list[vcurrent - 1]->value() >= v)
	    vcurrent = 0;
    }

    for (; vcurrent < vcount; vcurrent++) {
	c = list[vcurrent]->value();
	if (c == v)
	    return list[vcurrent];
	else if (c > v)
	    return NULL;
    }
    vcurrent--;
    return NULL;
}

//      Note: this could be a little wierd since it's actually returning
//      the style with value 'value' instead of list index 'value'
//      Plus: it's going to define the style if it doesn't already exist!
//
//      If you don't want extraneous styles getting inserted, be sure to
//      use the find operator first.  (I.e. If your reading a style value
//      and the style didn't previously exist, all the style information
//      will be undefined!
Flv_Style & Flv_Style_List::operator[](int value) {
    Flv_Style *
	p;

    if (find(value))		//      If it exists
	return *(list[vcurrent]);	//              return it

    p = new Flv_Style;
    p->value(value);
    insert(p);
    return *p;
}

--- NEW FILE: Flv_List.cxx ---
//      ======================================================================
//      File:    Flv_List.cxx - Flv_List implementation
//      Program: Flv_List - FLTK List Widget
//      Version: 0.1.0
//      Started: 11/21/99
//
//      Copyright (C) 1999 Laurence Charlton
//
//      Description:
//      Flv_List implements a scrollable list.  No data is stored
//      in the widget.  Supports headers/footers, natively supports a single
//      row height per list.    Row grids can be turned on and off.  Supports
//      no scroll bars as well as horizontal/vertical automatic or always
//      on scroll bars.
//      Uses absolute row references.
//
//      row -1 is defined as the row header
//      row -2 is defined as the row footer
//
[...1400 lines suppressed...]
    }
    if (edit_when() == FLV_EDIT_ALWAYS)
	vediting = true;
    if (nr && vediting) {
	get_style(s, nr);
	if (s.editor_defined() && !s.locked()) {
	    veditor = s.editor();
	    if (veditor) {
		edit_row = nr;
		load_editor(veditor, nr);
		veditor->damage(FL_DAMAGE_ALL);
		veditor->hide();
		veditor->show();
		Fl::focus(veditor);
	    }
	}
    }
    if (veditor && veditor->parent() != this)
	veditor->parent(this);
}

--- NEW FILE: makedepend ---

--- NEW FILE: Fl_Toggle_Tree.cxx ---
#include <stdio.h>
#include <FL/Fl_Input.H>
#include <FL/Fl_Group.H>
#include <FL/Fl.H>

#ifdef PIXIL
#include <nxapp.h>
#endif

#include <Flek/Fl_Toggle_Node.H>
#include <Flek/Fl_Toggle_Tree.H>
#include "pixmaps/tt_open_icon.xpm"
#include "pixmaps/tt_closed_icon.xpm"
#include "pixmaps/tt_file_small.xpm"
#include "pixmaps/tt_folder_small.xpm"

void
Fl_Toggle_Tree::select_range(Fl_Toggle_Node * start,
			     Fl_Toggle_Node * end, int add)
{

    Fl_Toggle_Node *tnode = (Fl_Toggle_Node *) first_;
    Fl_Toggle_Node *selecting = 0;
    selection_current_ = 0;
    selection_count_ = 0;

    traverse_start(tnode);

    while (tnode) {
	if (!selecting) {
	    if (tnode == start)
		selecting = end;
	    else if (tnode == end)
		selecting = start;
	}
	// add == 0 - pick one only (unpick rest)
	// add == 1 - add picked (never unpick)
	// add > 1  - toggle picked

	int tmp = tnode->selected_;
	if (selecting && (add > 1))
	    tnode->selected_ = !tnode->selected_;
	else if (selecting)
	    tnode->selected_ = 1;
	else if (add == 0)
	    tnode->selected_ = 0;

	tnode->changed_ = tmp != tnode->selected_;

	if (tnode == selecting)
	    selecting = 0;

	tnode = traverse_forward();
    }
    current_ = 0;
    if (selection_count() == 1)
	current_ = selection();
}

Fl_Pixmap *
    Fl_Toggle_Tree::s_closed_pixmap_ =
    0;
Fl_Pixmap *
    Fl_Toggle_Tree::s_opened_pixmap_ =
    0;

static const int
    no_columns[1] = {
0 };

Fl_Toggle_Tree::Fl_Toggle_Tree(int x, int y, int w, int h):
Fl_Toggle_Tree_Base(x, y, w, h)
{
    pixmap_offset_ = 16;
    label_offset_ = 40;
    current_ = 0;
    state_ = FL_TOGGLE_NONE;
    closed_pixmap_ = 0;
    opened_pixmap_ = 0;
    if (s_closed_pixmap_ == 0) {
	s_closed_pixmap_ = new Fl_Pixmap(tt_closed_icon_xpm);
    }
    if (s_opened_pixmap_ == 0) {
	s_opened_pixmap_ = new Fl_Pixmap(tt_open_icon_xpm);
    }
    closed_pixmap(s_closed_pixmap_);
    opened_pixmap(s_opened_pixmap_);
    column_widths_ = no_columns;
    column_char_ = '\t';

    selection_i_ = 0;
    selection_count_ = 0;
    selection_current_ = 0;

#if FL_MAJOR_VERSION == 1
    textfont_ = FL_HELVETICA;
#endif
    textsize_ = 12;

#ifdef PIXIL
    textcolor_ = NxApp::GlobalColor(APP_FG);
#else
    textcolor_ = FL_BLACK;
#endif

    edit_input_ = new Fl_Input(x, y, 0, 0);
    edit_input_->box(FL_FLAT_BOX);
#ifdef PIXIL
    edit_input_->color(NxApp::GlobalColor(APP_BG));
#else
    edit_input_->color(FL_WHITE);
#endif

#if FL_MAJOR_VERSION == 1
    edit_input_->textcolor(FL_BLACK);
    edit_input_->textfont(textfont_);
    edit_input_->textsize(textsize_);
#endif
    edit_callback((Fl_Callback *) edit_default_callback, this);
    edit_input_->
	when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY | FL_WHEN_NOT_CHANGED);

    edit_input_->hide();
    edit_on_reselect_ = 1;

#ifdef PIXIL
    color(NxApp::GlobalColor(HILIGHT_LITE));
    selection_color(NxApp::GlobalColor(HILIGHT));
    selection_label_color(NxApp::GlobalColor(HILIGHT_TEXT));
    alternate_color(NxApp::GlobalColor(HILIGHT_DARK));
#else
    color(FL_WHITE);
    selection_color(FL_BLACK);
    selection_label_color(FL_YELLOW);
    alternate_color(FL_LIGHT2);
#endif

    trim_color(FL_LIGHT1);
    draw_lines_ = 0;

#ifdef PIXIL
    NxApp::DefaultFont(this);
#endif
}

Fl_Toggle_Tree::~Fl_Toggle_Tree()
{
    delete edit_input_;
}

int cnt = 0;

void
Fl_Toggle_Tree::draw_node(int depth, int cy, Fl_Toggle_Node_Base * node)
{
    Fl_Toggle_Node *tnode = (Fl_Toggle_Node *) node;

    if (damage() == FL_DAMAGE_CHILD && !tnode->changed_ && damaged_ == 0) {
	return;
    }

    tnode->changed_ = 0;
    if (tnode->selected_) {
	fl_color(selection_color());
	fl_rectf(x(), cy + 1, w(), height_(tnode) - 1);
    } else {
	fl_color((cy - y()) & 1 ? color() : alternate_color());
	fl_rectf(x(), cy + 1, w(), height_(tnode) - 1);
    }
    fl_color(trim_color());
    fl_line(x(), cy, x() + w(), cy);
    fl_color(FL_BLACK);

    if (draw_lines_) {
	int i;
	Fl_Toggle_Node *n;
	fl_xyline(x() + depth * 16 + 8, cy + 8, x() + (depth + 1) * 16,
		  cy + 8);
	if (tnode->next_)
	    fl_xyline(x() + depth * 16 + 8, cy, x() + depth * 16 + 8,
		      cy + 16);
	else
	    fl_xyline(x() + depth * 16 + 8, cy, x() + depth * 16 + 8, cy + 8);
	for (i = depth - 1, n = (Fl_Toggle_Node *) tnode->up_; n; i--,
	     n = (Fl_Toggle_Node *) n->up_)
	    if (n->next_)
		fl_xyline(x() + i * 16 + 8, cy, x() + i * 16 + 8, cy + 16);
    }

    if (tnode->can_open_) {
	if (tnode->opened_)
	    opened_pixmap_->draw(x() + depth * 16, cy);
	else
	    closed_pixmap_->draw(x() + depth * 16, cy);
    }
#if FL_MAJOR_VERSION == 1
    if (tnode->selected_)
	textcolor(selection_label_color());
    else
	textcolor(labelcolor());
#endif

    if (tnode->label_) {
	int D = depth * 16 + label_offset_;
	draw_label(tnode->label_, D, x(), cy, w(), 16);
    }
    if (tnode->pixmap_) {
	tnode->pixmap_->draw(x() + depth * 16 + pixmap_offset_, cy + 1);
    }
}


void
Fl_Toggle_Tree::draw_label(char *str, int indent, int x, int y, int w, int h)
{
    const int *i = column_widths();

    while (w > 6) {		// do each tab-seperated field
	int w1 = w;		// width for this field
	char *e = 0;		// pointer to end of field or null if none
	if (*i) {		// find end of field and temporarily replace with 0
	    for (e = str; *e && *e != column_char(); e++);
	    if (*e) {
		*e = 0;
		w1 = *i++;
	    } else
		e = 0;
	}
	int size = textsize();
	Fl_Font font = textfont();
	Fl_Color lcol = textcolor();
	Fl_Align align = (Fl_Align) (FL_ALIGN_LEFT | FL_ALIGN_CLIP);
	// check for all the @-lines recognized by XForms:
	/*    while (*str == format_char() && *++str && *str != format_char()) {
	   switch (*str++) {
	   case 'l': case 'L': size = 24; break;
	   case 'm': case 'M': size = 18; break;
	   case 's': size = 11; break;
	   case 'b': font = (Fl_Font)(font|FL_BOLD); break;
	   case 'i': font = (Fl_Font)(font|FL_ITALIC); break;
	   case 'f': case 't': font = FL_COURIER; break;
	   case 'c': align = FL_ALIGN_CENTER; break;
	   case 'r': align = FL_ALIGN_RIGHT; break;
	   case 'B': 
	   fl_color((Fl_Color)strtol(str, &str, 10));
	   fl_rectf(x, y, w1, h);
	   break;
	   case 'C':
	   lcol = (Fl_Color)strtol(str, &str, 10);
	   break;
	   case 'F':
	   font = (Fl_Font)strtol(str, &str, 10);
	   break;
	   case 'N':
	   lcol = FL_INACTIVE_COLOR;
	   break;
	   case 'S':
	   size = strtol(str, &str, 10);
	   break;
	   case '-':
	   fl_color(FL_DARK3);
	   fl_line(x+3, y+h/2, x+w1-3, y+h/2);
	   fl_color(FL_LIGHT3);
	   fl_line(x+3, y+h/2+1, x+w1-3, y+h/2+1);
	   break;
	   case 'u':
	   case '_':
	   fl_color(lcol);
	   fl_line(x+3, y+h-1, x+w1-3, y+h-1);
	   break;
	   case '.':
	   goto BREAK;
	   case '@':
	   str--; goto BREAK;
	   }
	   }
	   BREAK:
	 */
	fl_font(font, size);
#if FL_MAJOR_VERSION == 1
#  if FL_MINOR_VERSION == 0
	if (!active_r())
	    lcol = inactive(lcol);
#  else
	if (!active_r())
	    lcol = fl_inactive(lcol);
#  endif
#endif
	//    if (((FL_BLINE*)v)->flags & SELECTED)
	//      lcol = contrast(lcol, selection_color());
	fl_color(lcol);
	fl_draw(str, x + indent, y + 1, w1 - indent, h + 1, align);
	if (!e)
	    break;		// no more fields...
	*e = column_char();	// put the seperator back
	x += w1;
	w -= w1;
	str = e + 1;
	indent = 0;
    }
}

void
Fl_Toggle_Tree::open(Fl_Toggle_Node * node)
{
    if (node->opened_ == 1)
	return;

    int th = Fl_Toggle_Tree_Base::open(node);

    damaged_ = node;
    if (th) {
	damage(FL_DAMAGE_TREE);
    } else {
	damage(FL_DAMAGE_CHILD);
    }
    if (th) {
	resize(x(), y(), w(), h() + th);
	parent()->damage(FL_DAMAGE_CHILD);
    }
}

void
Fl_Toggle_Tree::close(Fl_Toggle_Node * node)
{
    if (node->opened_ == 0)
	return;

    int th = Fl_Toggle_Tree_Base::close(node);

    damaged_ = node;
    if (th) {
	damage(FL_DAMAGE_TREE);
	resize(x(), y(), w(), h() - th);
	parent()->damage(FL_DAMAGE_SCROLL);
    } else {
	damage(FL_DAMAGE_CHILD);
    }
}

void
Fl_Toggle_Tree::edit(Fl_Toggle_Node * t, int cx, int cy)
{
    // printf("edit\n");
    if (!edit_input_->visible() && t) {
	// printf("%d %d %d %d %s\n",cx, cy, w()-(cx-x()), height_(t), t->label());
	edit_input_->resize(cx - 3, cy + 1, w() - (cx - 3 - x()),
			    height_(t) - 1);
	edit_input_->value(t->label());
	edit_input_->show();
	edit_input_->take_focus();
    }
}

void
Fl_Toggle_Tree::edit_default_callback(Fl_Input *, void *ptr)
{
    //  printf("default_edit_cb\n");
    Fl_Toggle_Tree *tree = (Fl_Toggle_Tree *) ptr;
    tree->end_edit();
}

void
Fl_Toggle_Tree::end_edit(void)
{
    //  printf("end_edit\n");
    if (current_) {
	((Fl_Toggle_Node *) current_)->label(strdup(edit_input_->value()));
    }
    edit_input_->hide();

    damaged_ = current_;
    damage(FL_DAMAGE_CHILD);
}

int
Fl_Toggle_Tree::handle(int event)
{
    //  printf("event: %d\n",event);
    static Fl_Toggle_Node *prev = 0;
    switch (event) {
    case FL_ENTER:
	return 1;
    case FL_KEYBOARD:
	return 0;
    case FL_SHORTCUT:
	return 0;
    case FL_RELEASE:{
	    if (edit_input_->visible()) {
		end_edit();
	    }
	    int depth;
	    int cy;
	    Fl_Toggle_Node *tnode =
		(Fl_Toggle_Node *) Fl_Toggle_Tree_Base::find(Fl::event_y(),
							     depth, cy);
	    if (Fl::event_x() < x() + depth * 16 + 16) {
		if (tnode->opened_) {
		    current_ = tnode;
		    state_ = FL_TOGGLE_OPENED;
		    do_callback();
		    close(tnode);
		} else {
		    current_ = tnode;
		    state_ = FL_TOGGLE_CLOSED;
		    do_callback();
		    open(tnode);
		}
	    } else {
		if (Fl::event_state(FL_SHIFT)) {
		    if (prev == 0)
			prev = tnode;
		    select_range(prev, tnode, 1);
		    //current_ = 0;
		    state_ = FL_TOGGLE_SELECT;
		    do_callback();
		} else if (Fl::event_state(FL_CTRL)) {
		    //if (!tnode->selected_)
		    select_range(tnode, tnode, Fl::event_state(FL_CTRL));
		    /*
		       else {
		       selection_current_ = NULL;
		       tnode->selected_ = 0;
		       tnode->changed_ = 1;
		       tnode = 0;
		       }
		       current_ = 0;
		     */
		    state_ = FL_TOGGLE_SELECT;
		    do_callback();
		} else {
		    select_range(tnode, tnode, 0);
		    state_ =
			Fl::event_clicks()? FL_TOGGLE_HIT : FL_TOGGLE_SELECT;
		    if (tnode == current_ && state_ == FL_TOGGLE_SELECT) {
			state_ = FL_TOGGLE_RESELECT;
		    }
		    //current_ = tnode;
		    if (state_ == FL_TOGGLE_RESELECT && edit_on_reselect_) {
			edit(tnode, x() + depth * 16 + label_offset_, cy);
		    }

		    do_callback();
		}
		damaged_ = 0;
		damage(FL_DAMAGE_CHILD);
		prev = tnode;
	    }
	}
	return 1;
    }
    return 1;
}

Fl_Toggle_Node *
Fl_Toggle_Tree::selection(void)
{

    if (current_ == 0)
	current_ = traverse_start();
    else {
	traverse_start(current_);
	current_ = traverse_forward();
    }

    while (current_) {
	if (((Fl_Toggle_Node *) current_)->selected_) {
	    return (Fl_Toggle_Node *) current_;
	}
	current_ = traverse_forward();
    }
    return 0;
}


int
Fl_Toggle_Tree::selection_count(void)
{
    if (selection_current_ == 0)
	selection_count_ = 0;

    if (selection_count_)
	return selection_count_;

    Fl_Toggle_Node *t;
    t = traverse_start();
    while (t) {
	if (t->selected_) {
	    selection_count_++;
	}
	t = traverse_forward();
    }

    return selection_count_;
}


Fl_Toggle_Node *
Fl_Toggle_Tree::selection(int i)
{
    int backwards = 0;

    if (selection_current_ == 0) {
	selection_current_ = traverse_start();
	selection_i_ = 0;
    } else {
	traverse_start(selection_current_);
	if (i > selection_i_) {
	    selection_current_ = traverse_forward();
	    selection_i_++;
	} else if (i < selection_i_) {
	    selection_current_ = traverse_backward();
	    selection_i_--;
	    backwards = 1;
	}
    }

    if (backwards) {
	while (selection_current_) {
	    //printf("traversed bw to:%s\n",selection_current_->label());
	    if (selection_current_->selected_) {
		if (i == selection_i_) {
		    return selection_current_;
		}
		selection_i_--;
	    }
	    selection_current_ = traverse_backward();
	}
    } else {
	while (selection_current_) {
	    if (selection_current_->selected_) {
		if (i == selection_i_) {
		    return selection_current_;
		}
		selection_i_++;
	    }
	    selection_current_ = traverse_forward();
	}
    }
    return 0;
}


void
Fl_Toggle_Tree::opened_pixmap(Fl_Pixmap * a)
{
    if (opened_pixmap_ && opened_pixmap_ != s_opened_pixmap_) {
	delete opened_pixmap_;
    }
    opened_pixmap_ = a;
}


void
Fl_Toggle_Tree::closed_pixmap(Fl_Pixmap * a)
{
    if (closed_pixmap_ && closed_pixmap_ != s_closed_pixmap_) {
	delete closed_pixmap_;
    }
    closed_pixmap_ = a;
}


int
Fl_Toggle_Tree::remove(char *a)
{
    Fl_Toggle_Node *curr;

    curr = find(a);
    if (curr)
	return remove(curr);

    return 0;
}


int
Fl_Toggle_Tree::remove(void *a)
{
    Fl_Toggle_Node *curr;

    curr = find(a);
    if (curr)
	return remove(curr);

    return 0;
}


Fl_Toggle_Node *
Fl_Toggle_Tree::find(char *a)
{
    Fl_Toggle_Node *curr = traverse_start();

    while (curr) {
	if (curr->label()) {
	    if (!strcmp(curr->label(), a)) {
		return curr;
	    }
	}
	curr = traverse_forward();
    }

    return 0;
}


Fl_Toggle_Node *
Fl_Toggle_Tree::find(void *a)
{
    Fl_Toggle_Node *curr = traverse_start();

    while (curr) {
	if (curr->label()) {
	    if (curr->user_data() == a) {
		return curr;
	    }
	}
	curr = traverse_forward();
    }

    return 0;
}


int
Fl_Toggle_Tree::sort_by_label(Fl_Toggle_Node_Base * a,
			      Fl_Toggle_Node_Base * b)
{
    return strcmp(((Fl_Toggle_Node *) a)->label(),
		  ((Fl_Toggle_Node *) b)->label());
}


void
Fl_Toggle_Tree::edit_callback(Fl_Callback * c, void *p)
{
    edit_input_->callback((Fl_Callback *) c, p);
}


void
Fl_Toggle_Tree::edit_callback(Fl_Callback * c)
{
    edit_input_->callback((Fl_Callback *) c);
}


void
Fl_Toggle_Tree::edit_callback(Fl_Callback0 * c)
{
    edit_input_->callback(c);
}


void
Fl_Toggle_Tree::edit_callback(Fl_Callback1 * c, long p)
{
    edit_input_->callback(c, p);
}

--- NEW FILE: Fl_Stock.cxx ---
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Pixmap.H>
#include <FL/fl_draw.H>

#include <Flek/Fl_Stock.H>
#include "pixmaps/stock_button_ok.xpm"
#include "pixmaps/stock_button_cancel.xpm"
#include "pixmaps/stock_button_yes.xpm"
#include "pixmaps/stock_button_no.xpm"
#include "pixmaps/stock_button_apply.xpm"
#include "pixmaps/stock_button_close.xpm"

#include "pixmaps/stock_add.xpm"
#include "pixmaps/stock_bottom.xpm"
#include "pixmaps/stock_top.xpm"
#include "pixmaps/stock_clear.xpm"
#include "pixmaps/stock_down_arrow.xpm"
#include "pixmaps/stock_up_arrow.xpm"
#include "pixmaps/stock_left_arrow.xpm"
#include "pixmaps/stock_right_arrow.xpm"
#include "pixmaps/stock_remove.xpm"
#include "pixmaps/stock_open.xpm"
#include "pixmaps/stock_new.xpm"

#include "pixmaps/stock_copy.xpm"
#include "pixmaps/stock_cut.xpm"
#include "pixmaps/stock_exec.xpm"
#include "pixmaps/stock_first.xpm"
#include "pixmaps/stock_help.xpm"
#include "pixmaps/stock_last.xpm"
#include "pixmaps/stock_save.xpm"
#include "pixmaps/stock_save_as.xpm"
#include "pixmaps/stock_search.xpm"
#include "pixmaps/stock_search_replace.xpm"

Fl_Stock_Button::Fl_Stock_Button(int x, int y, int w, int h, const char *l):
Fl_Button(x, y, w, h, l)
{
    // Scheme this :
#if FL_MAJOR_VERSION == 2
    label_size(10);
#else
    labelsize(10);
#endif
    //color (52);
    box(FL_FLAT_BOX);
}

void
Fl_Stock_Button::draw()
{
    if (type() == FL_HIDDEN_BUTTON)
	return;
#if FL_MAJOR_VERSION == 2
    Fl_Color col = draw_button(flags());
#else
    Fl_Color col = value()? selection_color() : color();
#  if FL_MINOR_VERSION == 0
    draw_box(value()? (down_box()? down_box() : down(box())) : box(), col);
#  else
    draw_box(value()? (down_box()? down_box() : fl_down(box())) : box(), col);
#  endif
#endif
    draw_label(x(), y(), w(), h(), col, flags());
}

void
Fl_Stock_Button::draw_label(int X, int Y, int W, int H,
			    Fl_Color c, Fl_Flags f)
{
    int tw = 0, th = 0;
    int iw = 0, ih = 0;

    int w, h;

    Fl_Image *image_ = image();
    const char *label_ = label();

    if (image_)
#if FL_MAJOR_VERSION == 2
	image_->measure(iw, ih);
#else
#  if FL_MINOR_VERSION == 0
	fl_measure_pixmap(image_->data, iw, ih);
#  else
	fl_measure_pixmap(image_->data(), iw, ih);
#  endif
#endif
    if (label_) {

	// Note: should tw be turned into an int so soon?  bdl
	// Anyway, I added the (int) to quiet the compiler.
#if FL_MAJOR_VERSION == 2
	fl_font(label_font(), label_size());
	tw = (int) fl_width(label_);
	th = label_size();
#else
	fl_font(labelfont(), labelsize());
	tw = (int) fl_width(label_);
	th = labelsize();
#endif
    }

    int spacer = 5;

    if ((f & FL_TEXT_ALIGN_TOP) || (f & FL_TEXT_ALIGN_BOTTOM)) {
	h = th + ih + spacer;
	w = ((tw > iw) ? tw : iw);	// max
    } else {
	w = tw + iw + spacer;
	h = ((th > ih) ? th : ih);	// max
    }

    int dx, dy;

    dx = X + (W / 2) - (w / 2);
    dy = Y + (H / 2) - (h / 2);

    if (f & FL_ALIGN_TOP) {
	if (f & FL_ALIGN_INSIDE)
	    dy = Y;
	else
	    dy = Y - h;
    }
    if (f & FL_ALIGN_BOTTOM) {
	if (f & FL_ALIGN_INSIDE)
	    dy = Y + H - h;
	else
	    dy = Y + H;
    }
    if (f & FL_ALIGN_LEFT) {
	if (f & FL_ALIGN_INSIDE)
	    dx = X;
	else
	    dx = X - dx;
    }
    if (f & FL_ALIGN_RIGHT) {
	if (f & FL_ALIGN_INSIDE)
	    dx = X + W - w;
	else
	    dx = X + W;
    }

    int tdx = dx, tdy = dy;
    int idx = dx, idy = dy;

    if (f & FL_TEXT_ALIGN_TOP) {
	idy = dy + th + spacer;
	idx += (w - iw) / 2;
	tdx += (w - tw) / 2;
    } else if (f & FL_TEXT_ALIGN_BOTTOM) {
	tdy = dy + ih + spacer;
	idx += (w - iw) / 2;
	tdx += (w - tw) / 2;
    } else if (f & FL_TEXT_ALIGN_LEFT) {
	idx = dx + tw + spacer;
	idy += (h - ih) / 2;
	tdy += (h - th) / 2;
    } else			// (f & FL_TEXT_ALIGN_RIGHT) // default
    {
	tdx = dx + iw + spacer;
	idy += (h - ih) / 2;
	tdy += (h - th) / 2;
    }

    int a = 0;
    if (!active_r())
	a = FL_INACTIVE;
    if (image_) {
#if FL_MAJOR_VERSION == 2
	fl_color((f & FL_INACTIVE) ? fl_inactive(c) : c);
	image_->draw(idx, idy, iw, ih, 0, 0);
#else
	image_->draw(idx, idy, iw, ih, a);
#endif
	//printf ("image = %d, %d, %d, %d\n", idx, idy, iw, ih);
    }

    if (label_ && *label_) {
#if FL_MAJOR_VERSION == 2
	fl_font(label_font(), label_size());
	//if (flags() & FL_SHORTCUT_LABEL) fl_draw_shortcut = 1;
	//printf ("label = %d, %d, %d, %d\n", tdx, tdy, tw, th);
	label_type()->draw(label_, tdx, tdy, tw, th, c, a);
	//fl_draw_shortcut = 0;
#else
	fl_font(labelfont(), labelsize());
	Fl_Widget::draw_label(tdx, tdy, tw, th, (Fl_Align) a);
#endif
    }

}

static Fl_Pixmap *Stock_Button_Ok_Image = 0;

Fl_Stock_Button_Ok::Fl_Stock_Button_Ok(int x, int y, int w, int h,
				       const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Ok_Image)
	Stock_Button_Ok_Image = new Fl_Pixmap(stock_button_ok_xpm);
    image(Stock_Button_Ok_Image);
    box(FL_THIN_UP_BOX);
}

static Fl_Pixmap *Stock_Button_Cancel_Image = 0;

Fl_Stock_Button_Cancel::Fl_Stock_Button_Cancel(int x, int y, int w, int h,
					       const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Cancel_Image)
	Stock_Button_Cancel_Image = new Fl_Pixmap(stock_button_cancel_xpm);
    image(Stock_Button_Cancel_Image);
    box(FL_THIN_UP_BOX);
}

static Fl_Pixmap *Stock_Button_Yes_Image = 0;

Fl_Stock_Button_Yes::Fl_Stock_Button_Yes(int x, int y, int w, int h,
					 const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Yes_Image)
	Stock_Button_Yes_Image = new Fl_Pixmap(stock_button_yes_xpm);
    image(Stock_Button_Yes_Image);
    box(FL_THIN_UP_BOX);
}

static Fl_Pixmap *Stock_Button_No_Image = 0;

Fl_Stock_Button_No::Fl_Stock_Button_No(int x, int y, int w, int h,
				       const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_No_Image)
	Stock_Button_No_Image = new Fl_Pixmap(stock_button_no_xpm);
    image(Stock_Button_No_Image);
    box(FL_THIN_UP_BOX);
}

static Fl_Pixmap *Stock_Button_Close_Image = 0;

Fl_Stock_Button_Close::Fl_Stock_Button_Close(int x, int y, int w, int h,
					     const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Close_Image)
	Stock_Button_Close_Image = new Fl_Pixmap(stock_button_close_xpm);
    image(Stock_Button_Close_Image);
    box(FL_THIN_UP_BOX);
}

static Fl_Pixmap *Stock_Button_Apply_Image = 0;

Fl_Stock_Button_Apply::Fl_Stock_Button_Apply(int x, int y, int w, int h,
					     const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Apply_Image)
	Stock_Button_Apply_Image = new Fl_Pixmap(stock_button_apply_xpm);
    image(Stock_Button_Apply_Image);
    box(FL_THIN_UP_BOX);
}


static Fl_Pixmap *Stock_Button_Add_Image = 0;

Fl_Stock_Button_Add::Fl_Stock_Button_Add(int x, int y, int w, int h,
					 const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Add_Image)
	Stock_Button_Add_Image = new Fl_Pixmap(stock_add_xpm);
    image(Stock_Button_Add_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Bottom_Image = 0;

Fl_Stock_Button_Bottom::Fl_Stock_Button_Bottom(int x, int y, int w, int h,
					       const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Bottom_Image)
	Stock_Button_Bottom_Image = new Fl_Pixmap(stock_bottom_xpm);
    image(Stock_Button_Bottom_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Clear_Image = 0;

Fl_Stock_Button_Clear::Fl_Stock_Button_Clear(int x, int y, int w, int h,
					     const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Clear_Image)
	Stock_Button_Clear_Image = new Fl_Pixmap(stock_clear_xpm);
    image(Stock_Button_Clear_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Down_Image = 0;

Fl_Stock_Button_Down::Fl_Stock_Button_Down(int x, int y, int w, int h,
					   const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Down_Image)
	Stock_Button_Down_Image = new Fl_Pixmap(stock_down_arrow_xpm);
    image(Stock_Button_Down_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Up_Image = 0;

Fl_Stock_Button_Up::Fl_Stock_Button_Up(int x, int y, int w, int h,
				       const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Up_Image)
	Stock_Button_Up_Image = new Fl_Pixmap(stock_up_arrow_xpm);
    image(Stock_Button_Up_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Left_Image = 0;

Fl_Stock_Button_Left::Fl_Stock_Button_Left(int x, int y, int w, int h,
					   const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Left_Image)
	Stock_Button_Left_Image = new Fl_Pixmap(stock_left_arrow_xpm);
    image(Stock_Button_Left_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Right_Image = 0;

Fl_Stock_Button_Right::Fl_Stock_Button_Right(int x, int y, int w, int h,
					     const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Right_Image)
	Stock_Button_Right_Image = new Fl_Pixmap(stock_right_arrow_xpm);
    image(Stock_Button_Right_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Previous_Image = 0;

Fl_Stock_Button_Previous::Fl_Stock_Button_Previous(int x, int y, int w, int h,
						   const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Previous_Image)
	Stock_Button_Previous_Image = new Fl_Pixmap(stock_left_arrow_xpm);
    image(Stock_Button_Previous_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Next_Image = 0;

Fl_Stock_Button_Next::Fl_Stock_Button_Next(int x, int y, int w, int h,
					   const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Next_Image)
	Stock_Button_Next_Image = new Fl_Pixmap(stock_right_arrow_xpm);
    image(Stock_Button_Next_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_New_Image = 0;

Fl_Stock_Button_New::Fl_Stock_Button_New(int x, int y, int w, int h,
					 const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_New_Image)
	Stock_Button_New_Image = new Fl_Pixmap(stock_new_xpm);
    image(Stock_Button_New_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Open_Image = 0;

Fl_Stock_Button_Open::Fl_Stock_Button_Open(int x, int y, int w, int h,
					   const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Open_Image)
	Stock_Button_Open_Image = new Fl_Pixmap(stock_open_xpm);
    image(Stock_Button_Open_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Remove_Image = 0;

Fl_Stock_Button_Remove::Fl_Stock_Button_Remove(int x, int y, int w, int h,
					       const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Remove_Image)
	Stock_Button_Remove_Image = new Fl_Pixmap(stock_remove_xpm);
    image(Stock_Button_Remove_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Top_Image = 0;

Fl_Stock_Button_Top::Fl_Stock_Button_Top(int x, int y, int w, int h,
					 const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Top_Image)
	Stock_Button_Top_Image = new Fl_Pixmap(stock_top_xpm);
    image(Stock_Button_Top_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Copy_Image = 0;

Fl_Stock_Button_Copy::Fl_Stock_Button_Copy(int x, int y, int w, int h,
					   const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Copy_Image)
	Stock_Button_Copy_Image = new Fl_Pixmap(stock_copy_xpm);
    image(Stock_Button_Copy_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Cut_Image = 0;

Fl_Stock_Button_Cut::Fl_Stock_Button_Cut(int x, int y, int w, int h,
					 const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Cut_Image)
	Stock_Button_Cut_Image = new Fl_Pixmap(stock_cut_xpm);
    image(Stock_Button_Cut_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Exec_Image = 0;

Fl_Stock_Button_Exec::Fl_Stock_Button_Exec(int x, int y, int w, int h,
					   const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Exec_Image)
	Stock_Button_Exec_Image = new Fl_Pixmap(stock_exec_xpm);
    image(Stock_Button_Exec_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_First_Image = 0;

Fl_Stock_Button_First::Fl_Stock_Button_First(int x, int y, int w, int h,
					     const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_First_Image)
	Stock_Button_First_Image = new Fl_Pixmap(stock_first_xpm);
    image(Stock_Button_First_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Help_Image = 0;

Fl_Stock_Button_Help::Fl_Stock_Button_Help(int x, int y, int w, int h,
					   const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Help_Image)
	Stock_Button_Help_Image = new Fl_Pixmap(stock_help_xpm);
    image(Stock_Button_Help_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Last_Image = 0;

Fl_Stock_Button_Last::Fl_Stock_Button_Last(int x, int y, int w, int h,
					   const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Last_Image)
	Stock_Button_Last_Image = new Fl_Pixmap(stock_last_xpm);
    image(Stock_Button_Last_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Save_Image = 0;

Fl_Stock_Button_Save::Fl_Stock_Button_Save(int x, int y, int w, int h,
					   const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Save_Image)
	Stock_Button_Save_Image = new Fl_Pixmap(stock_save_xpm);
    image(Stock_Button_Save_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Save_As_Image = 0;

Fl_Stock_Button_Save_As::Fl_Stock_Button_Save_As(int x, int y, int w, int h,
						 const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Save_As_Image)
	Stock_Button_Save_As_Image = new Fl_Pixmap(stock_save_as_xpm);
    image(Stock_Button_Save_As_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Search_Image = 0;

Fl_Stock_Button_Search::Fl_Stock_Button_Search(int x, int y, int w, int h,
					       const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Search_Image)
	Stock_Button_Search_Image = new Fl_Pixmap(stock_search_xpm);
    image(Stock_Button_Search_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

static Fl_Pixmap *Stock_Button_Search_Replace_Image = 0;

Fl_Stock_Button_Search_Replace::Fl_Stock_Button_Search_Replace(int x, int y,
							       int w, int h,
							       const char *l):
Fl_Stock_Button(x, y, w, h, l)
{
    if (!Stock_Button_Search_Replace_Image)
	Stock_Button_Search_Replace_Image =
	    new Fl_Pixmap(stock_search_replace_xpm);
    image(Stock_Button_Search_Replace_Image);
    set_flag(FL_TEXT_ALIGN_BOTTOM);
}

--- NEW FILE: Fl_Dockable_Window.cxx ---
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Pack.H>

#include <Flek/Fl_Dockable_Window.H>
#include "pixmaps/dock_grip_tile.xpm"
#include <stdio.h>

long
    Fl_Dockable_Window::gripper_width =
    10;
Fl_Dockable_Window *
    Fl_Dockable_Window::current =
    0;

void
Fl_Gripper::draw()
{
    if (_grippertype & FL_DRAGABLE) {
	// Draw the Gnome style gripper:
#if FL_MAJOR_VERSION == 1
	Fl_Color col = value()? selection_color() : color();
	draw_box(box(), col);
#else
	draw_box();
#endif
	// draw_label();

#if FL_MAJOR_VERSION == 1
	fl_push_clip(x() + 1, y() + 1, w() - 3, h() - 3);
#else
	fl_clip(x() + 1, y() + 1, w() - 3, h() - 3);
#endif

	for (int i = 0; i < w(); i += 6)
	    for (int j = 0; j < h(); j += 6)
		fl_draw_pixmap(grip_tile_xpm, i + 2, j + 2);

	fl_pop_clip();
    } else if (_grippertype & FL_SHOVABLE)
	Fl_Button::draw();
}

int
Fl_Gripper::handle(int event)
{
    int rval = Fl_Button::handle(event);
    int x_drag, y_drag;
    Fl_Dockable_Window *group = (Fl_Dockable_Window *) parent();
    Fl_Dockable_Window::current = group;

    switch (event) {
    case FL_PUSH:
	// Set the Fl_Dockable_Window that may eventually get docked.
	if (group->window() && (group->window()->modal()))
	    return 1;

	if (_grippertype & FL_DRAGABLE) {
	    Fl_Dockable_Window::current = (Fl_Dockable_Window *) parent();
	    x_down = Fl::event_x_root();
	    y_down = Fl::event_y_root();
	    x_first = Fl_Dockable_Window::current->x_root();
	    y_first = Fl_Dockable_Window::current->y_root();
	}
	return 1;

    case FL_DRAG:
    case FL_RELEASE:{
	    int x_up = Fl::event_x();
	    int y_up = Fl::event_y();

	    Fl_Pack *parent = (Fl_Pack *) group->parent();

	    if ((_grippertype & FL_SHOVABLE) && (event & FL_RELEASE)
		&& (group->parent()) && (x_up <= w() + 2)
		&& (y_up <= h() + 2)) {

#if 0
		int content_location = 0;
		// Apparently there is a bug somewhere in this algorithm.  bdl
		for (int i = 0; i < parent->children(); i++) {
		    if (parent->child(i)->type() != FL_WINDOW) {
			content_location = i;
		    }
		}

		int group_location = parent->find(group);
		int new_location =
		    content_location + (content_location - group_location) +
		    1;
#else
		// Simpler algorithm.  bdl
		// Shove it down until it hits the bottom, then shove it
		// up to the top.
		int new_location = parent->find(group) + 1;
		if (new_location >= parent->children())
		    new_location = 0;
#endif

		parent->insert(*((Fl_Widget *) group), new_location);
		parent->redraw();
		return 1;
	    }

	    if (!(_grippertype & FL_DRAGABLE))
		return 1;

	    if (group->window() && group->window()->modal())
		return 1;

	    x_drag = Fl::event_x_root();
	    y_drag = Fl::event_y_root();

	    int delta = ((x_drag + y_drag) - (x_down + y_down));

	    if (delta < 0)
		delta *= -1;

	    if (group->parent()) {
		if (delta > (FL_DOCK_DELTA * 2)) {
		    x_first = Fl_Dockable_Window::current->x_root();
		    y_first = Fl_Dockable_Window::current->y_root();

		    group->undock((x_first + (x_drag - x_down)),
				  (y_first + (y_drag - y_down)));

		    // Once undocked, give the window focus and continue dragging.
		    take_focus();
		    Fl::pushed(this);
		}
	    } else {
		// See if anyone want to dock with me..
		for (Fl_Window * o = Fl::first_window(); o;
		     o = Fl::next_window(o)) {
		    int ex = o->x_root();
		    int ey = o->y_root();
		    int ew = o->w();
		    int eh = o->h();

		    int cx = Fl::event_x_root();
		    int cy = Fl::event_y_root();

		    if (o->visible() && (cx > ex) && (cy > ey)
			&& (cx < (ew + ex)) && (cy < (eh + ey))) {
			// Send the host window a message that we want to dock with it.
			// printf ("Fl_Dockable_Window:: Attempting to dock.\n");
			if (Fl::handle(FL_DOCK, o)) {
			    // printf ("Fl_Dockable_Window:: Docking.\n");
			    // redraw();
			    if (event != FL_RELEASE) {
				// I want to send JUST the drag event.  Not push!
				// Right now it just stops dragging after a successful dock.
				// take_focus();
				// Fl::pushed(this);
			    }
			    break;
			}
		    }
		}
	    }

	    // Isn't it docked?
	    if (!group->docked())
		// Move the window around following the pointer.
		group->position((x_first + (x_drag - x_down)),
				(y_first + (y_drag - y_down)));
	}

	return 1;
    }

    return rval;
}

void
Fl_Gripper::grippertype(unsigned char t)
{
    _grippertype = t;
}

unsigned char
Fl_Gripper::grippertype()
{
    return _grippertype;
}


Fl_Dockable_Window::Fl_Dockable_Window(int x, int y, int w, int h,
				       const char *l)
:  Fl_Window(x, y, w, h, l)
{
    create_dockable_window();
}

Fl_Dockable_Window::Fl_Dockable_Window(int w, int h, const char *l)
    :
Fl_Window(w, h, l)
{
    create_dockable_window();
}

void
Fl_Dockable_Window::create_dockable_window()
{
    clear_border();
    uw_ = w();
    uh_ = h();
    gripper = new Fl_Gripper(0, 0, gripper_width, h());
    _docked = 0;
    contents = new Fl_Window(gripper_width, 0, w(), h());
    resizable(contents);
    grippertype(FL_DRAGABLE);
    begin();
}

void
Fl_Dockable_Window::show()
{
    Fl_Window::show();
    gripper->show();
}

int
Fl_Dockable_Window::handle(int event)
{
    int rval;
    switch (event) {
    case FL_SHOW:
	rval = Fl_Window::handle(event);
	contents->show();
	return rval;
    case FL_HIDE:
	contents->hide();
	break;
    }
    return Fl_Window::handle(event);
}

void
Fl_Dockable_Window::undock(int x, int y)
{
    _docked = 0;
    // printf ("undocking..\n");
    if (parent()) {
	Fl_Group *group = (Fl_Group *) parent();
	hide();

	group->remove((Fl_Widget *) this);

	// printf ("Let dock handle the event..\n");
	// Give the dock an opportunity to handle the event.
	Fl::handle(FL_UNDOCK, group->window());

	// group->redraw();

	if ((x > -1) && (y > -1))
	    position(x, y);

	// printf("positioned x, y = %d,%d", x, y);

	size(uw_, uh_);

	// printf ("show me!!\n");
	show();
	// layout();
    }
}

void
Fl_Dockable_Window::grippertype(unsigned char t)
{
    // Set the type of the gripper.
    gripper->grippertype(t);

    if ((t & FL_DRAGABLE) || (t & FL_SHOVABLE)) {
	contents->resize(gripper_width, 0, w(), h());
	gripper->show();
    } else {
	contents->resize(0, 0, w(), h());
	gripper->hide();
    }
}

unsigned char
Fl_Dockable_Window::grippertype()
{
    return gripper->grippertype();
}

--- NEW FILE: FJPEG.cxx ---
#include <Flek/math.H>
#include <Flek/FFile.H>
#include <Flek/FImage.H>
#include <Flek/FJPEG.H>

extern "C"
{
#include <jpeglib.h>
}

/*
 * Code to read JPEG images.  Boiler plate stuff snarfed from the 
 * libjpeg examples.
 */

FImage *
FJPEG::read(char *filename)
{

    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    FILE *infile;
    int row_stride;

    if ((infile = fopen(filename, "rb")) == NULL) {
	fprintf(stderr, "can't open %s\n", filename);
	return 0;
    }
    // Step 1: allocate and initialize JPEG decompression object
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);

    // Step 2: specify data source (eg, a file)
    jpeg_stdio_src(&cinfo, infile);

    // Step 3: read file parameters with jpeg_read_header()
    (void) jpeg_read_header(&cinfo, TRUE);

    // Step 5: Start decompressor  
    (void) jpeg_start_decompress(&cinfo);

    FImage *rval =
	new FImage(cinfo.output_width, cinfo.output_height,
		   cinfo.output_components);
    row_stride = cinfo.output_width * cinfo.output_components;

    while (cinfo.output_scanline < cinfo.output_height) {
	unsigned char *i[1];
	i[0] =
	    *(rval->begin(cinfo.output_height - cinfo.output_scanline - 1));
	(void) jpeg_read_scanlines(&cinfo, i, 1);
    }

    // Step 7: Finish decompression 
    (void) jpeg_finish_decompress(&cinfo);

    // Step 8: Release JPEG decompression object and allocated memory
    jpeg_destroy_decompress(&cinfo);

    fclose(infile);
    return rval;
}

int
FJPEG::write(char *filename, FImage * data, int quality)
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;

    if (data->channels() == 3)
	cinfo.in_color_space = JCS_RGB;
    else if (data->channels() == 1)
	cinfo.in_color_space = JCS_GRAYSCALE;
    else
	return -1;

    FILE *outfile;
    int row_stride;
    unsigned char *row_pointer[1];
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);

    if ((outfile = fopen(filename, "wb")) == NULL) {
	fprintf(stderr, "can't open %s\n", filename);
	return -1;
    }

    jpeg_stdio_dest(&cinfo, outfile);
    cinfo.image_width = data->width();
    cinfo.image_height = data->height();
    if (data->channels() == 3)
	cinfo.in_color_space = JCS_RGB;
    else if (data->channels() == 1)
	cinfo.in_color_space = JCS_GRAYSCALE;
    else
	return -1;
    cinfo.input_components = data->channels();
    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, quality, TRUE);
    jpeg_start_compress(&cinfo, TRUE);
    row_stride = data->width() * data->channels();

    while (cinfo.next_scanline < cinfo.image_height) {
	row_pointer[0] =
	    *(data->begin(cinfo.image_height - cinfo.next_scanline - 1));
	(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }

    jpeg_finish_compress(&cinfo);
    fclose(outfile);
    jpeg_destroy_compress(&cinfo);
    return 0;
}

--- NEW FILE: FPNM.cxx ---
#include <Flek/FPNM.H>

// CET - FIXME - this shouldn't use libstdc++ if it can be avoided- libstdc++
// causes compatibility problems under linux.  Maybe should use the regular
// stdio.h stuff?
#include <iostream.h>
#include <fstream.h>

static int
skip_comments(ifstream & input)
{
    char c;
    // Skip space up to first comment.
    input.setf(ios::skipws);
    input >> c;
    input.unsetf(ios::skipws);
    if (c != '#') {
	input.putback(c);
	//input.unget ();
	input.setf(ios::skipws);
	return 0;
    }
    while (c == '#') {
	while (c != '\n') {
	    input >> c;
	    if (input.bad())
		return 1;
	}
	input >> c;
	if (input.bad())
	    return 1;
    }
    input.putback(c);
    //input.unget ();
    input.setf(ios::skipws);
    return 0;
}

bool
FPNM::valid(char *filename)
{
    ifstream input;
    int type;
    char c;

    input.open(filename);
    if (input.bad())
	return false;

    input.unsetf(ios::skipws);

    // Check the magic number
    input >> c;
    if (!((c == 'P') || (c == 'p')))
	return false;

    input >> c;
    type = c - 48;

    if ((type < 1) || (type > 7))
	return false;

    input.close();

    return true;
}

FImage *
FPNM::read(char *filename)
{
    ifstream input;
    int width, height;
    int type;
    int depth;
    char c;

    input.open(filename);
    if (input.bad())
	return 0;

    // Check the magic number
    input >> c;
    if (!((c == 'P') || (c == 'p')))
	return 0;

    // the file type
    input >> c;
    type = c - 48;

    // We support types 1-6 and nonstandard 7
    if ((type < 1) || (type > 7))
	return 0;

    if (skip_comments(input))
	return 0;

    switch (type) {
    case 2:
    case 3:
    case 5:
    case 6:
    case 7:
	input >> width;

	if (skip_comments(input))
	    return 0;

	input >> height;

	if (skip_comments(input))
	    return 0;

	input >> depth;

	break;
    case 1:
    case 4:
	input >> width;

	if (skip_comments(input))
	    return 0;

	input >> height;

	break;
    }

    input.unsetf(ios::skipws);

    // Single whitespace before input.
    input >> c;

    FImage *img = new FImage(width, height);
    FImage::iterator begin;
    FImage::iterator end;
    FImage::iterator i;
    uchar *pixel;
    int row;

    switch (type) {
    case 1:			// ASCII B&W
	for (row = height - 1; row >= 0; row--) {
	    begin = img->begin(row);
	    end = img->end(row);
	    int c;

	    for (i = begin; i != end; i++) {
		pixel = *i;
		input >> c;

		if (input.bad())
		    return img;	// return corrupt image.

		if (c)
		    pixel[0] = 255;
		else
		    pixel[0] = 0;
		pixel[1] = pixel[2] = pixel[0];
		pixel[3] = 255;
	    }
	}
	break;
    case 2:			// ASCII GRAY
	input.unsetf(ios::skipws);
	for (row = height - 1; row >= 0; row--) {
	    unsigned int g;
	    begin = img->begin(row);
	    end = img->end(row);

	    for (i = begin; i != end; i++) {
		pixel = *i;
		input >> g;
		pixel[0] = g;	// red
		pixel[1] = pixel[2] = pixel[0];	// blue & green
		pixel[3] = 255;	// alpha
		if (input.bad())
		    return img;	// return corrupt image.
	    }
	}
	break;
    case 3:			// ASCII RGB
	input.unsetf(ios::skipws);
	for (row = height - 1; row >= 0; row--) {
	    unsigned int r;
	    unsigned int g;
	    unsigned int b;
	    begin = img->begin(row);
	    end = img->end(row);

	    for (i = begin; i != end; i++) {
		pixel = *i;
		input >> r;
		pixel[0] = r;	// red
		input >> g;
		pixel[1] = g;	// green
		input >> b;
		pixel[2] = b;	// blue
		pixel[3] = 255;	// alpha
		if (input.bad())
		    return img;	// return corrupt image.
	    }
	}
	break;
    case 4:			// RAW BITPACKED B&W
	for (row = height - 1; row >= 0; row--) {
	    begin = img->begin(row);
	    end = img->end(row);
	    char c;
	    int cx = 0;

	    for (i = begin; i != end;) {
		input >> c;
		if (input.bad())
		    return img;	// return corrupt image.

		for (int j = 0; (j < 8) && (cx + j < width); j++) {
		    pixel = *i;
		    if (0x80 & (c << j))
			pixel[0] = pixel[1] = pixel[2] = 0;
		    else
			pixel[0] = pixel[1] = pixel[2] = 255;
		    pixel[3] = 255;
		    i++;
		}
		cx += 8;
	    }
	}
	break;
    case 5:			// RAW GRAY
	for (row = height - 1; row >= 0; row--) {
	    begin = img->begin(row);
	    end = img->end(row);

	    for (i = begin; i != end; i++) {
		pixel = *i;
		input >> pixel[0];	// red
		pixel[1] = pixel[2] = pixel[0];	// blue & green
		pixel[3] = 255;	// alpha
		if (input.bad())
		    return img;	// return corrupt image.
	    }
	}
	break;
    case 6:			// RAW RGB
	for (row = height - 1; row >= 0; row--) {
	    begin = img->begin(row);
	    end = img->end(row);

	    for (i = begin; i != end; i++) {
		pixel = *i;
		input >> pixel[0];	// red
		input >> pixel[1];	// green
		input >> pixel[2];	// blue
		pixel[3] = 255;	// alpha
		if (input.bad())
		    return img;	// return corrupt image.
	    }
	}
	break;
    case 7:			// RAW RGBA (nonstandard)
	for (row = height - 1; row >= 0; row--) {
	    begin = img->begin(row);
	    end = img->end(row);

	    for (i = begin; i != end; i++) {
		pixel = *i;
		input >> pixel[0];	// red
		input >> pixel[1];	// green
		input >> pixel[2];	// blue
		input >> pixel[3];	// alpha
		if (input.bad())
		    return img;	// return corrupt image.
	    }
	}
	break;
    }

    input.close();

    return img;
}

int
FPNM::write(char *filename, FImage * img)
{
    ofstream output;
    FImage::iterator begin;
    FImage::iterator end;
    FImage::iterator i;
    uchar *pixel;

    output.open(filename);
    if (output.bad())
	return 1;

    output << "P6" << endl;
    output << "# CREATOR: Flek's FPNM::write ()" << endl;
    output << img->width() << " " << img->height() << endl;
    output << "255 ";

    int height = img->height();

    for (int row = height - 1; row >= 0; row--) {
	begin = img->begin(row);
	end = img->end(row);

	for (i = begin; i != end; i++) {
	    pixel = *i;
	    output << pixel[0];	// red
	    output << pixel[1];	// green
	    output << pixel[2];	// blue
	}
    }
    output.close();
    return 0;
}

--- NEW FILE: Fl_Better_Window.cxx ---
#include <Flek/Fl_Better_Window.H>

#ifdef NANOX
#include <FL/n_x.h>
#else
#include <FL/x.H>
#endif

// get_window_borders by "Jason Ertel" <jertel at simulation.com>

int
Fl_Better_Window::get_window_borders(Fl_Window * win, int &left, int &right,
				     int &top, int &bottom)
{
#if defined(_WIN32)
    RECT myRect;
    int result;

    result = GetWindowRect(fl_xid(win), &myRect);
    left = win->x() - myRect.left;
    right = myRect.right - (win->x() + win->w());
    top = win->y() - myRect.top;
    bottom = myRect.bottom - (win->y() + win->h());

    return result;
#else

    /* JHC - this is incorrect - but I don't believe this function is used, so just something to hide our
       shame */

#ifdef NANOX
    GR_WINDOW_ID current = fl_xid(win);
    GR_WINDOW_INFO wi;

    GrGetWindowInfo(current, &wi);

    left = win->x() - wi.x;
    right = wi.width - win->w() - left;
    top = win->y() - wi.y;
    bottom = wi.height - win->h() - top;

    return 1;
#else
    Window root, parent, *children, current;
    unsigned int childrenCount;
    XWindowAttributes attrs;
    int status = 1;

    current = fl_xid(win);

    while (status) {
	status =
	    XQueryTree(fl_display, current, &root, &parent, &children,
		       &childrenCount);
	if (parent == root)
	    break;
	current = parent;
    }
    if (status) {
	XGetWindowAttributes(fl_display, current, &attrs);
	left = win->x() - attrs.x;
	right = attrs.width - win->w() - left;
	top = win->y() - attrs.y;
	bottom = attrs.height - win->h() - top;
	return 1;
    } else {
	left = 0;
	right = 0;
	top = 0;
	bottom = 0;
	return 0;
    }
#endif
#endif
}

--- NEW FILE: Fl_Toggle_Tree_Base.cxx ---
#include <stdio.h>		// printf
#include <stdlib.h>		// qsort

#include <Flek/Fl_Toggle_Node_Base.H>
#include <Flek/Fl_Toggle_Tree_Base.H>

Fl_Toggle_Tree_Base::Fl_Toggle_Tree_Base(int x, int y, int w, int h):
Fl_Widget(x, y, w, h)
{
    first_ = 0;
    t_current_ = 0;
    top_ = 0;
    top_depth_ = 0;
    damaged_ = 0;
}

void
Fl_Toggle_Tree_Base::draw_node(int depth, int cy, Fl_Toggle_Node_Base *)
{
    fl_color(FL_BLACK);
    fl_rectf(x(), cy, depth * 16, 16);
    fl_color(FL_WHITE);
    fl_rectf(x() + depth * 16, cy, w() - depth * 16, 16);
}

Fl_Toggle_Node_Base *
Fl_Toggle_Tree_Base::find(int fy, int &depth, int &ry)
{
    int cy = parent()->y() + top_yoffset_;
    int ey = parent()->y() + parent()->h();

    if (fy < cy)
	return 0;

    depth = top_depth_;
    Fl_Toggle_Node_Base *node = top_;
    traverse_start(top_);

    while (cy < ey && node) {
	ry = cy;
	cy += height(node);
	if (cy > fy)
	    return node;
	node = traverse_forward(1, depth);
    }
    return 0;
}

void
Fl_Toggle_Tree_Base::update_height(void)
{
    resize(x(), y(), w(), total_height(first_));
}

void
Fl_Toggle_Tree_Base::draw(void)
{
    //  printf("Fl_Toggle_Tree_Base::draw %d %d\n",x(),y());
    update_top();
    int cy = parent()->y() + top_yoffset_;
    int ey = parent()->y() + parent()->h();
    int depth = top_depth_;
    Fl_Toggle_Node_Base *node = top_;
    int drawing = 0;
    //printf("DAMAGE %d %d %d\n",damage(),FL_DAMAGE_ALL,FL_DAMAGE_CHILD);
    if (damage() == FL_DAMAGE_ALL)
	drawing = 1;
    if (damage() == FL_DAMAGE_CHILD && damaged_ == 0)
	drawing = 1;
    while (cy < ey && node) {
	if (damaged_ == node) {
	    if (damage() == FL_DAMAGE_CHILD) {
		draw_node(depth, cy, node);
		return;
	    }
	    drawing = 1;
	}
	//printf("%s %d\n",(char*) node->data(),drawing);
	if (drawing)
	    draw_node(depth, cy, node);
	cy += height(node);
	if (node->vsub_) {
	    //printf("has sub\n");
	    node = node->vsub_;
	    depth++;
	} else if (node->next_) {
	    //printf("has no sub\n");
	    node = node->next_;
	} else {
	    while (node && !node->next_) {
		node = node->up_;
		depth--;
	    }
	    if (node)
		node = node->next_;
	}
    }
    fl_color(parent()->color());
    fl_rectf(x(), cy, w(), ey - cy);
}

int (*s_node_compare_) (Fl_Toggle_Node_Base *, Fl_Toggle_Node_Base *) = 0;

int
Fl_Toggle_Tree_Base::s_compare_(void *a, void *b)
{
    Fl_Toggle_Node_Base *nodeA = *(Fl_Toggle_Node_Base **) a;
    Fl_Toggle_Node_Base *nodeB = *(Fl_Toggle_Node_Base **) b;
    return s_node_compare_(nodeA, nodeB);
}

int
Fl_Toggle_Tree_Base::s_compare_reverse_(void *a, void *b)
{
    Fl_Toggle_Node_Base *nodeA = *(Fl_Toggle_Node_Base **) a;
    Fl_Toggle_Node_Base *nodeB = *(Fl_Toggle_Node_Base **) b;
    return -s_node_compare_(nodeA, nodeB);
}

Fl_Toggle_Node_Base *
Fl_Toggle_Tree_Base::sort_(Fl_Toggle_Node_Base * start,
			   int (*compar) (Fl_Toggle_Node_Base *,
					  Fl_Toggle_Node_Base *), int down,
			   sort_order order)
{
    int i;
    Fl_Toggle_Node_Base *node;

    i = 0;
    node = start;

    while (node) {
	node = node->next_;
	i++;
    }
    Fl_Toggle_Node_Base **array = new Fl_Toggle_Node_Base *[i];

    i = 0;
    node = start;
    while (node) {
	array[i] = node;
	node = node->next_;
	i++;
    }
    s_node_compare_ = compar;

    if (order == REVERSE_SORT) {
	qsort(array, i, sizeof(Fl_Toggle_Node_Base *),
	      (int (*)(const void *, const void *)) s_compare_reverse_);
    } else {
	qsort(array, i, sizeof(Fl_Toggle_Node_Base *),
	      (int (*)(const void *, const void *)) s_compare_);
    }

    start = array[0];
    int j = 1;
    node = start;
    node->prev_ = 0;		//james
    while (j < i) {
	node->next_ = array[j];
	node->next_->prev_ = node;
	node = node->next_;
	j++;
    }
    node->next_ = 0;

    if (down) {
	node = start;
	while (node) {
	    if (node->sub_)
		node->sub_ = sort_tree(node->sub_, compar, order);
	    if (node->vsub_)
		node->vsub_ = node->sub_;
	    node = node->next_;
	}
    }

    delete[]array;

    return start;
}

Fl_Toggle_Node_Base *
Fl_Toggle_Tree_Base::sort(Fl_Toggle_Node_Base * start,
			  int (*compar) (Fl_Toggle_Node_Base *,
					 Fl_Toggle_Node_Base *),
			  sort_order order)
{
    if (first_)
	return sort_(start, compar, 0, order);
    return 0;
}

Fl_Toggle_Node_Base *
Fl_Toggle_Tree_Base::sort_tree(Fl_Toggle_Node_Base * start,
			       int (*compar) (Fl_Toggle_Node_Base *,
					      Fl_Toggle_Node_Base *),
			       sort_order order)
{
    if (first_)
	return sort_(start, compar, 1, order);
    return 0;
}

void
Fl_Toggle_Tree_Base::
sort(int (*compar) (Fl_Toggle_Node_Base *, Fl_Toggle_Node_Base *),
     sort_order order)
{
    if (first_)
	first_ = top_ = sort(first_, compar, order);
}

void
Fl_Toggle_Tree_Base::
sort_tree(int (*compar) (Fl_Toggle_Node_Base *, Fl_Toggle_Node_Base *),
	  sort_order order)
{
    if (first_)
	first_ = top_ = sort_tree(first_, compar, order);
}

void
Fl_Toggle_Tree_Base::update_top(void)
{
    Fl_Toggle_Node_Base *node = first_;
    int py = parent()->y();
    int ly = y();
    int h = 0;
    int depth = 0;

    while (node && ly + (h = height(node)) <= py) {
	ly += h;
	if (node->vsub_) {
	    node = node->vsub_;
	    depth++;
	} else if (node->next_) {
	    node = node->next_;
	} else {
	    while (node && !node->next_) {
		node = node->up_;
		depth--;
	    }
	    if (node)
		node = node->next_;
	}
    }

    top_ = node;
    top_depth_ = depth;
    top_yoffset_ = ly - py;
}

int
Fl_Toggle_Tree_Base::total_height(Fl_Toggle_Node_Base * node)
{
    int ret = 0;
    int depth = 1;
    while (node) {
	ret += height(node);
	if (node->vsub_) {
	    node = node->vsub_;
	    depth++;
	} else if (node->next_) {
	    node = node->next_;
	} else {
	    while (node && !node->next_) {
		node = node->up_;
		depth--;
		if (depth <= 0)
		    node = 0;
	    }
	    if (node)
		node = node->next_;
	}
    }
    return ret;
}

int
Fl_Toggle_Tree_Base::height(Fl_Toggle_Node_Base *)
{
    return 17;
}

Fl_Toggle_Node_Base *
Fl_Toggle_Tree_Base::traverse_start()
{
    t_current_ = first_;
    return t_current_;
}

void
Fl_Toggle_Tree_Base::traverse_start(Fl_Toggle_Node_Base * a)
{
    t_current_ = a;
}

void
Fl_Toggle_Tree_Base::traverse_up(void)
{
    if (t_current_ && t_current_->up_)
	t_current_ = t_current_->up_;
}


Fl_Toggle_Node_Base *
Fl_Toggle_Tree_Base::traverse_forward(int visible, int &depth)
{

    if (visible) {
	if (t_current_ && t_current_->vsub_ != 0) {
	    t_current_ = t_current_->vsub_;
	    depth++;
	    return t_current_;
	}
    } else {
	if (t_current_ && t_current_->sub_ != 0) {
	    t_current_ = t_current_->sub_;
	    depth++;
	    return t_current_;
	}
    }

    if (t_current_ && t_current_->next_ != 0) {
	t_current_ = t_current_->next_;
	return t_current_;
    }

    while (t_current_ && !t_current_->next_) {
	t_current_ = t_current_->up_;
	depth--;
    }
    if (t_current_)
	t_current_ = t_current_->next_;

    return t_current_;
}

Fl_Toggle_Node_Base *
Fl_Toggle_Tree_Base::traverse_forward()
{
    int d;
    return traverse_forward(0, d);
}

Fl_Toggle_Node_Base *
Fl_Toggle_Tree_Base::traverse_backward()
{
    if (t_current_ && t_current_->prev_) {
	t_current_ = t_current_->prev_;
	while (t_current_->sub_) {
	    t_current_ = t_current_->sub_;
	    while (t_current_->next_) {
		t_current_ = t_current_->next_;
		if (t_current_->next_ == 0 && t_current_->sub_) {
		    t_current_ = t_current_->sub_;
		}
	    }
	}
    } else {
	t_current_ = t_current_->up_;
    }
    return t_current_;
}

void
Fl_Toggle_Tree_Base::add_next(Fl_Toggle_Node_Base * node)
{
    if (!first_) {
	first_ = node;
	t_current_ = node;
    } else {
	if (t_current_ == 0)
	    t_current_ = first_;
	node->next_ = t_current_->next_;
	if (t_current_->next_) {
	    t_current_->next_->prev_ = node;
	}
	t_current_->next_ = node;
	node->prev_ = t_current_;
	node->up_ = t_current_->up_;
	t_current_ = node;
    }

    update_height();
    parent()->damage(FL_DAMAGE_CHILD);
    redraw();
}

void
Fl_Toggle_Tree_Base::add_sub(Fl_Toggle_Node_Base * node)
{

    if (!first_) {
	first_ = node;
	t_current_ = node;
    } else {
	if (t_current_ == 0)
	    t_current_ = first_;
	node->next_ = t_current_->sub_;

	if (t_current_->sub_)
	    t_current_->sub_->prev_ = node;
	node->prev_ = 0;
	t_current_->sub_ = node;

	if (t_current_->opened_)
	    t_current_->vsub_ = node;

	node->up_ = t_current_;
	t_current_ = node;
    }

    update_height();
    parent()->damage(FL_DAMAGE_CHILD);
    redraw();
}

int
Fl_Toggle_Tree_Base::remove(Fl_Toggle_Node_Base * a)
{
    Fl_Toggle_Node_Base *temp = a->sub_;

    while (temp != 0) {		// Remove all children
	remove(temp);
	temp = a->sub_;
    }

    if (a->prev_) {
	a->prev_->next_ = a->next_;
	if (a->next_)
	    a->next_->prev_ = a->prev_;
    } else if (a->up_) {
	Fl_Toggle_Node_Base *o = a->up_;
	o->sub_ = a->next_;
	if (o->opened_)
	    o->vsub_ = a->next_;
	else
	    o->vsub_ = 0;

	if (a->next_) {
	    a->next_->up_ = o;
	    a->next_->prev_ = a->prev_;
	}
    }

    if (a == first_) {
	if (a->next_) {
	    first_ = a->next_;
	    first_->up_ = 0;
	    first_->prev_ = 0;
	} else {
	    first_ = 0;
	    top_ = 0;
	}
    }

    if (a == current_) {
	if (a->up_)
	    current_ = a->up_;
	else if (a->prev_)
	    current_ = a->prev_;
	else
	    current_ = 0;
    }

    if (a == t_current_) {
	if (a->up_)
	    t_current_ = a->up_;
	else if (a->prev_)
	    t_current_ = a->prev_;
	else
	    t_current_ = 0;
    }

    update_height();
    parent()->damage(FL_DAMAGE_CHILD);
    redraw();

    delete a;
    a = 0;

    return 1;
}

int
Fl_Toggle_Tree_Base::clear()
{
    while (first_)
	remove(first_);
    return 1;
}

int
Fl_Toggle_Tree_Base::close(Fl_Toggle_Node_Base * node)
{
    int th = total_height(node->vsub_);
    node->opened_ = 0;
    node->vsub_ = 0;
    return th;
}

int
Fl_Toggle_Tree_Base::open(Fl_Toggle_Node_Base * node)
{
    node->vsub_ = node->sub_;
    int th = total_height(node->vsub_);
    node->opened_ = 1;
    return th;
}

--- NEW FILE: FVector.cxx ---
#include <Flek/FVector2.H>
#include <Flek/FVector3.H>
#include <Flek/FVector4.H>

#include <Flek/FMatrix3x3.H>
#include <Flek/FMatrix4x4.H>

void
FVector3::copy_from(FVector4 const &v)
{
    elem[0] = v[0];
    elem[1] = v[1];
    elem[2] = v[2];
}

void
FVector3::copy_from(FVector2 const &v)
{
    elem[0] = v[0];
    elem[1] = v[1];
    elem[0] = 0;
}

void
FVector2::copy_from(FVector4 const &v)
{
    elem[0] = v[0];
    elem[1] = v[1];
}

void
FVector2::copy_from(FVector3 const &v)
{
    elem[0] = v[0];
    elem[1] = v[1];
}

void
FVector4::copy_from(FVector3 const &v)
{
    elem[0] = v[0];
    elem[1] = v[1];
    elem[2] = v[2];
}

void
FVector4::copy_from(FVector2 const &v)
{
    elem[0] = v[0];
    elem[1] = v[1];
}

/*
  The following functions are defined outside the class so that they use the
  friend versions of member functions instead of the member functions themselves
*/

FMatrix4x4
operator *(const FMatrix4x4 & mat1, const FMatrix4x4 & mat2)
{
    FMatrix4x4 prod, trans;

    // Find the transpose of the 2nd matrix
    trans = transpose(mat2);

    // The columns of mat2 are now the rows of trans
    // Multiply appropriate rows and columns to get the product
    prod.row[0].set(mat1.row[0] * trans.row[0],
		    mat1.row[0] * trans.row[1],
		    mat1.row[0] * trans.row[2], mat1.row[0] * trans.row[3]);
    prod.row[1].set(mat1.row[1] * trans.row[0],
		    mat1.row[1] * trans.row[1],
		    mat1.row[1] * trans.row[2], mat1.row[1] * trans.row[3]);
    prod.row[2].set(mat1.row[2] * trans.row[0],
		    mat1.row[2] * trans.row[1],
		    mat1.row[2] * trans.row[2], mat1.row[2] * trans.row[3]);
    prod.row[3].set(mat1.row[3] * trans.row[0],
		    mat1.row[3] * trans.row[1],
		    mat1.row[3] * trans.row[2], mat1.row[3] * trans.row[3]);
    return prod;
}

FVector4
operator *(const FVector4 & vec, const FMatrix4x4 & mat)
{
    return (transpose(mat) * vec);
}

/*
  The following functions are defined outside the class so that they use the
  friend versions of member functions instead of the member functions themselves
*/

FMatrix3x3
operator *(const FMatrix3x3 & mat1, const FMatrix3x3 & mat2)
{
    FMatrix3x3 prod, trans;

    // Find the transpose of the 2nd matrix
    trans = transpose(mat2);

    // The columns of mat2 are now the rows of trans
    // Multiply appropriate rows and columns to get the product
    prod.row[0].set(mat1.row[0] * trans.row[0],
		    mat1.row[0] * trans.row[1], mat1.row[0] * trans.row[2]);
    prod.row[1].set(mat1.row[1] * trans.row[0],
		    mat1.row[1] * trans.row[1], mat1.row[1] * trans.row[2]);
    prod.row[2].set(mat1.row[2] * trans.row[0],
		    mat1.row[2] * trans.row[1], mat1.row[2] * trans.row[2]);
    return prod;
}

FVector3
operator *(const FVector3 & vec, const FMatrix3x3 & mat)
{
    return (transpose(mat) * vec);
}




More information about the dslinux-commit mailing list