[comp.sources.sun] v01i008: palette, a colormix tool, Part 01/02

mcgrew@dartagnan.rutgers.edu (Charles Mcgrew) (05/19/89)

Submitted-by: Wayne Mesard <mesard@bbn.com>
Posting-number: Volume 1, Issue 8
Archive-name: palette/part01

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	README.mod
#	MANIFEST
#	mono.icon
#	palette.c
#	palette.l
#	patchlevel.h
#	wsm_types.h
# This archive created: Thu May 18 14:03:18 1989
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(1094 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^	X//' << \SHAR_EOF > 'README'
	XTo build palette, type
	X
	X    make
	X
	XTo install it, change the MANDIR, MANEXT and BINDIR in the Makefile as
	Xappropriate, and type
	X
	X    make install
	X
	XSee the man page for details.
	X
	XPalette was developed on a color Sun 3/160 under SunOS 3.4.  
	XAny bug reports, comments or suggestions would be appreciated
	X
	Xpalette - a colormap editor
	XCopyright (c) 1988 Wayne Mesard
	X
	XThis is free software.  It may be reproduced, retransmitted,
	Xredistributed and otherwise propogated at will, provided that
	Xno monetary profit is realized and that this notice remains
	Xintact and in place.
	X
	XChanges made from v1.0p0 to v1.1:
	X
	X o  Fixed the hideous missing 2nd arg to open(2).
	X o  Arrow keys now handled the "right" wrong way [sic].
	X o  Added Delete Map ability.
	X o  New file format: RGB Lists.
	X o  Added ability to load from files (in any of the 4 supported formats).
	X o  Various minor fixes to control names, minor performance improvements, etc.
	X o  Added more runtime error messages.
	X
	XWayne Mesard
	XBolt Beranek and Newman          mesard@bbn.com
	X70 Fawcett St.                   617-873-1878
	XCambridge, MA  02138
	X
	X
SHAR_EOF
if test 1094 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 1094 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'README.mod'" '(265 characters)'
if test -f 'README.mod'
then
	echo shar: will not over-write existing file "'README.mod'"
else
sed 's/^	X//' << \SHAR_EOF > 'README.mod'
	X   This is a thing that will allow you to futz with your color levels.
	XThe author says it works under 3.4, and it also works under 4.0.
	X
	X   I could not get the color icon (which is not used in the actual
	Xcode anyway) to work, but the b&w icon works fine.
	X
	XCharles
	X
SHAR_EOF
if test 265 -ne "`wc -c < 'README.mod'`"
then
	echo shar: error transmitting "'README.mod'" '(should have been 265 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'MANIFEST'" '(620 characters)'
if test -f 'MANIFEST'
then
	echo shar: will not over-write existing file "'MANIFEST'"
else
sed 's/^	X//' << \SHAR_EOF > 'MANIFEST'
	X   File Name		Archive #	Description
	X----------------------------------------------------------
	X README                     1	
	X README.mod		    1   Moderators comments
	X MANIFEST                   1	This shipping list
	X Makefile                   2	
	X canvas.c                   2	
	X color.icon                 2	
	X desktop.c                  2	
	X hash.c                     2	
	X hash.h                     2	
	X left_arrow.pr              2	
	X mono.icon                  1	
	X palette.c                  1	
	X palette.l                  1	
	X patchlevel.h               1	
	X right_arrow.pr             2	
	X wsm_types.h                1	
	X
SHAR_EOF
if test 620 -ne "`wc -c < 'MANIFEST'`"
then
	echo shar: error transmitting "'MANIFEST'" '(should have been 620 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'mono.icon'" '(1934 characters)'
if test -f 'mono.icon'
then
	echo shar: will not over-write existing file "'mono.icon'"
else
sed 's/^	X//' << \SHAR_EOF > 'mono.icon'
	X/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
	X */
	X	0x7FFF,0xFFFF,0xFFFF,0xFFFE,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
	X	0xE000,0x0000,0x0000,0x0007,0xC000,0x0000,0x0000,0x0003,
	X	0xC000,0x0000,0x0000,0x0003,0xC000,0x007F,0xFFE0,0x0003,
	X	0xC000,0x0380,0x001E,0x0003,0xC000,0x0C00,0x0001,0x8003,
	X	0xC000,0x0802,0x0000,0xC003,0xC000,0x31E7,0x0000,0x6003,
	X	0xC000,0xC3FF,0x8000,0x1003,0xC001,0x03FF,0x8000,0x0803,
	X	0xC006,0x03FF,0xC000,0x0403,0xC008,0x01FF,0xC000,0x0603,
	X	0xC010,0xA1FF,0x8000,0x0303,0xC011,0xB1FF,0x8000,0x0103,
	X	0xC022,0xE9FF,0x8000,0x0103,0xC047,0x7CFC,0x0000,0x0103,
	X	0xC04D,0xDC00,0x0000,0x0103,0xC08B,0xB400,0x0000,0x0103,
	X	0xC086,0xEC00,0x0000,0x0303,0xC107,0x7E00,0x0000,0x0603,
	X	0xC105,0xBC00,0x0000,0x0403,0xC103,0xE800,0x0000,0x1803,
	X	0xC210,0x3000,0x0001,0xE003,0xC22A,0x0000,0xFC03,0x0003,
	X	0xC255,0x0001,0x0206,0x0003,0xC2AA,0x8002,0x010C,0x0003,
	X	0xC255,0x0004,0x0088,0x0003,0xC2AA,0x8004,0x0098,0x0003,
	X	0xC255,0x0004,0x0090,0x0003,0xC2AA,0x8004,0x0090,0x0003,
	X	0xC255,0x0004,0x0090,0x0003,0xC22A,0x8004,0x0090,0x0003,
	X	0xC254,0x0002,0x0110,0x0003,0xC200,0x1801,0x0210,0x0003,
	X	0xC201,0xC000,0xFC08,0x0003,0xC206,0x2400,0x000C,0x0003,
	X	0xC211,0x9000,0x0006,0x0003,0xC210,0x8400,0x0003,0x0003,
	X	0xC10A,0x1000,0x0000,0xC003,0xC112,0xAC00,0x0000,0x2003,
	X	0xC118,0xC800,0x0000,0x1803,0xC087,0xA0A0,0x0000,0x0403,
	X	0xC080,0x2018,0x0000,0x0203,0xC0CB,0xC232,0x0000,0x0203,
	X	0xC021,0x032C,0x0000,0x0203,0xC030,0x0484,0x0000,0x0203,
	X	0xC010,0x05A1,0x0000,0x0203,0xC008,0x0208,0x0000,0x0203,
	X	0xC00C,0x04A2,0x0000,0x0203,0xC004,0x0158,0x0000,0x0203,
	X	0xC003,0x00A4,0x0000,0x0403,0xC000,0xC010,0x0000,0x0803,
	X	0xC000,0x7048,0x0000,0x1003,0xC000,0x0800,0x0000,0x2003,
	X	0xC000,0x0700,0x0001,0xC003,0xC000,0x00FC,0x000E,0x0003,
	X	0xC000,0x0003,0xFFF0,0x0003,0xC000,0x0000,0x0000,0x0003,
	X	0xC000,0x0000,0x0000,0x0003,0xE000,0x0000,0x0000,0x0007,
	X	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0x7FFF,0xFFFF,0xFFFF,0xFFFE
	X
SHAR_EOF
if test 1934 -ne "`wc -c < 'mono.icon'`"
then
	echo shar: error transmitting "'mono.icon'" '(should have been 1934 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'palette.c'" '(38447 characters)'
if test -f 'palette.c'
then
	echo shar: will not over-write existing file "'palette.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'palette.c'
	X/* 
	X * palette.c - This file contains the program's main processing routines 
	X *             including all window creation, event handlers and 
	X *             the routines for manipulating colors and color maps.
	X *             
	X *             Exported routines:
	X *               main (duh)
	X *               MakeCMS
	X */
	X
	X/**************************************************************************
	X *      palette - a colormap editor
	X *      Copyright (c) 1988 Wayne Mesard                                   *
	X *                                                                        *
	X *      This is free software.  It may be reproduced, retransmitted,      *
	X *      redistributed and otherwise propogated at will, provided that     *
	X *      no monetary profit is realized and that this notice remains       *
	X *      intact and in place.                                              *
	X *                                                                        *
	X *      Please direct bug reports, code enhancements and comments         *
	X *      to mesard@BBN.COM.                                                *
	X *                                                                        *
	X **************************************************************************/
	X
	X#include <suntool/sunview.h>
	X#include <suntool/panel.h>
	X#include <suntool/canvas.h>
	X#include <strings.h>
	X#include <ctype.h>
	X#include <stdio.h>
	X
	X#include "patchlevel.h"
	X#include "wsm_types.h"
	X#include "hash.h"
	X
	X#define MAX_COLORS 256
	X#define MAX_BRIGHTNESS 255
	X
	X#define MAX_COLORS_STR_LEN 9
	X
	X#define PALETTE_H 160
	X#define BUTT_SIZE 11
	X#define NUM_MY_WINDOWS 4
	X
	Xenum updatecolor_msg {U_NEW_STATE, U_NEW_COLOR, U_NEW_CMS};
	X
	X
	Xstatic short mono_image[] = {
	X#  include "mono.icon"
	X};
	Xmpr_static(mono_pr, 64, 64, 1, mono_image);
	XDEFINE_ICON_FROM_IMAGE(mono_icon, mono_image);
	X
	Xstatic short color_image[] = {
	X#  include "color.icon"
	X};
	Xmpr_static(color_pr, 64, 64, 8, color_image);
	Xstatic Icon color_icon;
	X
	X
	Xstatic short left_arrow_array[] = {
	X#  include "left_arrow.pr"
	X};
	Xmpr_static(left_arrow, 16, 16, 1, left_arrow_array);
	X
	Xstatic short right_arrow_array[] = {
	X#  include "right_arrow.pr"
	X};
	Xmpr_static(right_arrow, 16, 16, 1, right_arrow_array);
	X
	X
	Xstatic use_colormap = false;
	Xstatic boolean shallow_walkP = false;
	Xstatic Pixwin *my_pixies[NUM_MY_WINDOWS];
	X
	Xstatic Panel_item sliders[3];
	Xstatic Panel_item avg_markers[3];
	Xstatic Panel_item new_map_size;
	Xstatic Panel_item step_size_item;
	Xstatic Panel_item proportional_item;
	Xstatic Panel_item reset_on_reread;
	Xstatic Panel_item file_type;
	Xstatic Panel_item file_name;
	X
	Xstatic int cur_entry = 0;
	Xstatic int cur_range_end = 0;
	Xstatic int cur_size;
	Xstatic char *cur_name;
	Xstatic Panel_item cur_cms_item;
	Xstatic struct cms_map cur_map;
	X
	Xstatic unsigned char clipboard_red[MAX_COLORS];
	Xstatic unsigned char clipboard_green[MAX_COLORS];
	Xstatic unsigned char clipboard_blue[MAX_COLORS];
	Xstatic struct cms_map clipboard = 
	X          {clipboard_red, clipboard_green, clipboard_blue};
	Xstatic short clipboard_entries = 0;
	X
	Xstatic Frame frame;
	Xstatic int my_frame_fd;
	Xstatic Panel control_panel, table_panel;
	Xstatic Panel_item cur_color_item;
	Xstatic Panel_item msg_item;
	Xstatic char frame_cms_name[CMS_NAMESIZE];
	Xstatic char subwins_cms_name[CMS_NAMESIZE];
	X
	X
	Xmain(argc, argv)
	Xint argc;
	Xchar **argv;
	X{
	X    extern int Get_Root();
	X    void InitWindow(), Message();
	X    void SelectCMS();
	X    boolean WalkWinTree();
	X    int rootfd, i;
	X
	X    for (i = argc; i>1;)
	X	if (argv[--i][0] == '-')
	X	    if (argv[i][1] == 'f')
	X		shallow_walkP = true;
	X	    else if (argv[i][1] == 's')
	X		use_colormap = true;
	X         /* else This must be an arg for the frame. */
	X
	X    H_MakeNull();
	X    InitWindow(argc, argv);
	X
	X    if ((rootfd=Get_Root(frame))==-1) {
	X	fprintf(stderr, "%s: Error opening screen's root window\n", argv[0]);
	X	exit(1);
	X	/*NOTREACHED*/
	X    }
	X
	X    if (!WalkWinTree(rootfd, shallow_walkP))
	X	Message("<Error: CMS table full.  Not all windows processed.>", 0);
	X    (void) close(rootfd);
	X    (void) WalkWinTree(my_frame_fd, true); /* Since it's not in the tree yet. */
	X    cur_name = NULL;
	X    SelectCMS(frame_cms_name);
	X    window_main_loop(frame);
	X}
	X
	X
	X
	X/* 
	X * InitWindow - Set up all the windows and panel items.
	X */
	X
	Xstatic void InitWindow(argc, argv)
	Xint argc;
	Xchar **argv;
	X{
	X    extern Pixwin *MakePalette();
	X    void slider_notify();
	X    void ArrowEvent();
	X    void Copy(), Paste();
	X    Panel_setting KeyedEntry(), NumericText();
	X    void ClickOnCMS();
	X    void KeyEvent();
	X    void UseColorMap(), WalkDepth();
	X    void ResizeCanvas(), CanvasEvent();
	X    void CreateNewMap(), Reread_Maps(), Save(), Load(), Quit();
	X
	X    static char RGBName[][6] = {"Red  ", "Green", "Blue "};
	X    Canvas canvas;
	X    char buf[16];
	X    int i, row = -1;
	X    unsigned char **ptr;
	X
	X
	X    color_icon = icon_create(ICON_IMAGE, &color_pr, 0);
	X
	X    frame = window_create(NULL, FRAME,
	X			  FRAME_NO_CONFIRM, TRUE,
	X			  FRAME_ICON, &mono_icon,
	X			  FRAME_LABEL, "Palette",
	X			  FRAME_ARGS, argc, argv,
	X			  WIN_CONSUME_KBD_EVENT, WIN_NO_EVENTS,
	X			  0);
	X
	X    control_panel = window_create(frame, PANEL, 
	X				PANEL_ITEM_X_GAP, 5,
	X				WIN_EVENT_PROC, KeyEvent,
	X				0);
	X
	X    for (i= -1; ++i<3;) {
	X	(void) sprintf(buf, "%s:", RGBName[i]);
	X	switch (i) {
	X	  case 0:
	X	    ptr = &(cur_map.cm_red);
	X	    break;
	X	  case 1:
	X	    ptr = &(cur_map.cm_green);
	X	    break;
	X	  case 2:
	X	    ptr = &(cur_map.cm_blue);
	X	    break;
	X	}
	X
	X	sliders[i] = panel_create_item(control_panel, PANEL_SLIDER,
	X			  PANEL_ITEM_X, ATTR_COL(0),
	X			  PANEL_ITEM_Y, ATTR_ROW(++row),
	X			  PANEL_LABEL_STRING, buf,
	X			  PANEL_CLIENT_DATA, ptr,
	X			  PANEL_MIN_VALUE, 0,
	X			  PANEL_MAX_VALUE, MAX_COLORS-1,
	X			  PANEL_SHOW_RANGE, FALSE,
	X			  PANEL_SLIDER_WIDTH, MAX_COLORS,
	X			  PANEL_NOTIFY_PROC, slider_notify,
	X			  PANEL_NOTIFY_LEVEL, PANEL_ALL,
	X			  0);
	X
	X	avg_markers[i] = panel_create_item(control_panel, PANEL_MESSAGE,
	X			  PANEL_LABEL_STRING, "*",
	X			  PANEL_LABEL_BOLD, TRUE,
	X			  0);
	X
	X	(void) panel_create_item(control_panel, PANEL_BUTTON,
	X			  PANEL_LABEL_IMAGE, &left_arrow,
	X			  PANEL_NOTIFY_PROC, ArrowEvent,
	X			  PANEL_CLIENT_DATA, sliders[i],
	X			  0);
	X
	X	(void) panel_create_item(control_panel, PANEL_BUTTON,
	X			  PANEL_LABEL_IMAGE, &right_arrow,
	X			  PANEL_NOTIFY_PROC, ArrowEvent,
	X			  PANEL_CLIENT_DATA, sliders[i],
	X			  0);
	X
	X	
	X    }
	X    panel_set(control_panel, PANEL_ITEM_X_GAP, 15, 0);
	X
	X    cur_color_item =  panel_create_item(control_panel, PANEL_TEXT,
	X			     PANEL_ITEM_X, ATTR_COL(0),
	X			     PANEL_ITEM_Y, ATTR_ROW(++row),
	X			     PANEL_LABEL_BOLD, TRUE,
	X			     PANEL_LABEL_STRING, "Current Color:",
	X			     PANEL_VALUE_STORED_LENGTH,  MAX_COLORS_STR_LEN,
	X			     PANEL_VALUE_DISPLAY_LENGTH, MAX_COLORS_STR_LEN,
	X			     PANEL_NOTIFY_LEVEL, PANEL_ALL,
	X			     PANEL_NOTIFY_PROC, KeyedEntry,
	X			     0);
	X
	X    (void) panel_create_item(control_panel, PANEL_BUTTON,
	X			     PANEL_NOTIFY_PROC, Copy,
	X			     PANEL_LABEL_IMAGE,
	X			       panel_button_image(control_panel,
	X						  "Copy", BUTT_SIZE, 0),
	X			     0);
	X
	X    (void) panel_create_item(control_panel, PANEL_BUTTON,
	X			     PANEL_NOTIFY_PROC, Paste,
	X			     PANEL_LABEL_IMAGE,
	X			       panel_button_image(control_panel,
	X						  "Paste", BUTT_SIZE, 0),
	X			     0);
	X
	X    msg_item = panel_create_item(control_panel, PANEL_MESSAGE, 
	X				 PANEL_ITEM_X, ATTR_COL(0),
	X				 PANEL_ITEM_Y, ATTR_ROW(++row),
	X				 PANEL_LABEL_STRING, " ",
	X				 0);
	X			       
	X    (void) panel_create_item(control_panel, PANEL_BUTTON,
	X			     PANEL_ITEM_X, ATTR_COL(0),
	X			     PANEL_ITEM_Y, ATTR_ROW(++row),
	X			     PANEL_NOTIFY_PROC, CreateNewMap,
	X			     PANEL_LABEL_IMAGE,
	X			       panel_button_image(control_panel,
	X						  "New Map", BUTT_SIZE, 0),
	X			     0);
	X
	X    new_map_size = panel_create_item(control_panel, PANEL_CYCLE,
	X			     PANEL_ITEM_X, ATTR_COL(15),
	X			     PANEL_ITEM_Y, ATTR_ROW(row),
	X			     PANEL_LABEL_BOLD, TRUE,
	X			     PANEL_LABEL_STRING, "New Map Size:",
	X			     PANEL_CHOICE_STRINGS, 
	X			       "  2","  4","  8"," 16"," 32",
	X			       " 64","128","256", 0,
	X			     PANEL_VALUE, 7,
	X			     0);
	X
	X    proportional_item =  panel_create_item(control_panel, PANEL_CYCLE,
	X			     PANEL_ITEM_X, ATTR_COL(15),
	X			     PANEL_ITEM_Y, ATTR_ROW(++row),
	X			     PANEL_LABEL_STRING, "Uniform Steps:",
	X			     PANEL_LABEL_BOLD, TRUE,
	X			     PANEL_CHOICE_STRINGS, "Yes", "No", 0,
	X			     PANEL_VALUE, 0,
	X			     0);
	X
	X    /* A bug in SunOS 3.4 causes the following item to be 2 pixels above
	X     * the row using screen.r.14.  I have no idea why.  Other fonts don't
	X     * seem to be effected, and other sizes of screen are shifted by 
	X     * different distances.  Anyway, the "+2" below should be adjusted or
	X     * removed as your system configuration dictates.
	X     */
	X    step_size_item = panel_create_item(control_panel, PANEL_TEXT,
	X			     PANEL_LABEL_BOLD, TRUE,
	X			     PANEL_LABEL_STRING, "Step Size:",
	X			     PANEL_ITEM_Y, ATTR_ROW(row)+2,
	X			     PANEL_VALUE_STORED_LENGTH,  3,
	X			     PANEL_VALUE_DISPLAY_LENGTH, 3,
	X			     PANEL_VALUE, "10",
	X			     PANEL_NOTIFY_LEVEL, PANEL_ALL,
	X			     PANEL_NOTIFY_PROC, NumericText,
	X			     0);
	X
	X    (void) panel_create_item(control_panel, PANEL_BUTTON,
	X			     PANEL_ITEM_X, ATTR_COL(0),
	X			     PANEL_ITEM_Y, ATTR_ROW(++row),
	X			     PANEL_NOTIFY_PROC, Reread_Maps,
	X			     PANEL_LABEL_IMAGE,
	X			       panel_button_image(control_panel,
	X						  "Reread Maps", BUTT_SIZE, 0),
	X			     0);
	X			     
	X    (void) panel_create_item(control_panel, PANEL_CYCLE,
	X			     PANEL_ITEM_X, ATTR_COL(15),
	X			     PANEL_ITEM_Y, ATTR_ROW(row),
	X			     PANEL_NOTIFY_PROC, WalkDepth,
	X			     PANEL_LABEL_BOLD, TRUE,
	X			     PANEL_LABEL_STRING, "Read From:",
	X			     PANEL_CHOICE_STRINGS, 
	X			       "All windows", "Top level frames", 0,
	X			     PANEL_VALUE, shallow_walkP,
	X			     0);
	X
	X    reset_on_reread = panel_create_item(control_panel, PANEL_CYCLE,
	X			     PANEL_ITEM_X, ATTR_COL(15),
	X			     PANEL_ITEM_Y, ATTR_ROW(++row),
	X			     PANEL_LABEL_BOLD, TRUE,
	X			     PANEL_LABEL_STRING, "On Reread:",
	X			     PANEL_CHOICE_STRINGS, 
	X			       "Reset table first", "Don't reset table", 0,
	X			     0);
	X
	X    (void) panel_create_item(control_panel, PANEL_BUTTON,
	X			     PANEL_ITEM_X, ATTR_COL(0),
	X			     PANEL_ITEM_Y, ATTR_ROW(++row),
	X			     PANEL_NOTIFY_PROC, Save,
	X			     PANEL_LABEL_IMAGE,
	X			       panel_button_image(control_panel,
	X						  "Save", BUTT_SIZE, 0),
	X			     0);
	X
	X    file_type = panel_create_item(control_panel, PANEL_CYCLE,
	X			     PANEL_ITEM_X, ATTR_COL(15),
	X			     PANEL_LABEL_BOLD, TRUE,
	X			     PANEL_LABEL_STRING, "Save Type:",
	X			     PANEL_CHOICE_STRINGS,
	X			       "RGB arrays", "RGB list", "Clear raster file",
	X			       "Palette raster file", 0,
	X			     0);
	X
	X
	X    (void) panel_create_item(control_panel, PANEL_BUTTON,
	X			     PANEL_ITEM_X, ATTR_COL(0),
	X			     PANEL_ITEM_Y, ATTR_ROW(++row),
	X			     PANEL_NOTIFY_PROC, Load,
	X			     PANEL_LABEL_IMAGE,
	X			       panel_button_image(control_panel,
	X						  "Load", BUTT_SIZE, 0),
	X			     0);
	X
	X
	X    file_name = panel_create_item(control_panel, PANEL_TEXT,
	X			     PANEL_ITEM_X, ATTR_COL(15),
	X			     PANEL_ITEM_Y, ATTR_ROW(row),
	X			     PANEL_LABEL_BOLD, TRUE,
	X			     PANEL_LABEL_STRING, "File Name:",
	X			     PANEL_VALUE_STORED_LENGTH,  128,
	X			     PANEL_VALUE_DISPLAY_LENGTH, 24,
	X			     PANEL_VALUE, "palette.rgb",
	X			     0);
	X
	X    (void) panel_create_item(control_panel, PANEL_BUTTON,
	X			     PANEL_ITEM_X, ATTR_COL(0),
	X			     PANEL_ITEM_Y, ATTR_ROW(++row),
	X			     PANEL_NOTIFY_PROC, Quit,
	X			     PANEL_LABEL_IMAGE,
	X			       panel_button_image(control_panel,
	X						  "Quit", BUTT_SIZE, 0),
	X			     0);
	X
	X    (void) panel_create_item(control_panel, PANEL_CYCLE,
	X			     PANEL_ITEM_X, ATTR_COL(15),
	X			     PANEL_NOTIFY_PROC, UseColorMap,
	X			     PANEL_LABEL_BOLD, TRUE,
	X			     PANEL_LABEL_STRING, "Palette's Colormap:",
	X			     PANEL_CHOICE_STRINGS, "Its own", "Selected", 0,
	X			     PANEL_VALUE, use_colormap,
	X			     0);
	X
	X    window_fit(control_panel);
	X    window_fit_width(frame);
	X    table_panel = window_create(frame, PANEL, 
	X				PANEL_ITEM_X_GAP, 60,
	X				PANEL_EVENT_PROC, ClickOnCMS,
	X				WIN_VERTICAL_SCROLLBAR, scrollbar_create(0),
	X				WIN_ROWS, 3,
	X				WIN_IGNORE_KBD_EVENT, WIN_ASCII_EVENTS,
	X				WIN_CONSUME_PICK_EVENT, MS_LEFT,
	X				WIN_INPUT_DESIGNEE, 
	X			          i = (int) window_get(control_panel,
	X						       WIN_DEVICE_NUMBER),
	X				0);
	X
	X    canvas = window_create(frame, CANVAS, 
	X				   CANVAS_RESIZE_PROC, ResizeCanvas,
	X				   CANVAS_FIXED_IMAGE, FALSE,
	X				   CANVAS_AUTO_CLEAR, FALSE,
	X				   WIN_CONSUME_PICK_EVENTS,
	X				     WIN_UP_EVENTS, LOC_DRAG,
	X				     MS_LEFT, MS_MIDDLE, 0,
	X				   WIN_INPUT_DESIGNEE, i,
	X				   WIN_EVENT_PROC, CanvasEvent,
	X				   WIN_BELOW, table_panel,
	X				   WIN_HEIGHT, PALETTE_H,
	X				   0);
	X
	X    my_pixies[0] = MakePalette(canvas);
	X    my_pixies[1] = (Pixwin *) window_get(frame, WIN_PIXWIN);
	X    my_pixies[2] = (Pixwin *) window_get(control_panel, WIN_PIXWIN);
	X    my_pixies[3] = (Pixwin *) window_get(table_panel, WIN_PIXWIN);
	X
	X    pw_getcmsname(my_pixies[1], frame_cms_name);
	X    pw_getcmsname(my_pixies[2], subwins_cms_name);
	X
	X    my_frame_fd = (int) window_get(frame, WIN_FD);
	X    window_fit_height(frame);
	X}
	X
	X
	X
	X/* 
	X * Message - Put a string in the message line (with an optional numeric 
	X *           argument.
	X */
	X
	Xstatic void Message(s, i)
	Xchar *s;
	Xint i;
	X{
	X    char buf[80];
	X    
	X    (void) sprintf(buf, s, i);
	X    panel_set(msg_item, PANEL_LABEL_STRING, buf, 0);
	X}
	X
	X
	X
	X/* 
	X * SelectEntry - Do the work when the user selects a new color or range 
	X *               of colors.  index need not be less than range_end.  The 
	X *               sliders and the Current Color indicator are updated.  
	X *               And the current color(s) are highlighted in the palette.
	X *               (Single colors are not highlighted if the colormap is of 
	X *               size 2.)  
	X *              
	X *               If index or range_end are illegal values, the routine 
	X *               silently exits.
	X */
	X
	Xstatic void SelectEntry(index, range_end)
	Xint index, range_end;
	X{
	X    extern void HighlightSwatch(), BoxSwatches(), DrawPalette();
	X    unsigned char **ptr;
	X    char buf[MAX_COLORS_STR_LEN+1];
	X    int i, j, val, prev;
	X    boolean avgP, avg_existsP = false;
	X
	X    if (index > range_end) {
	X	if (range_end == -1)
	X	    range_end = index;
	X	else {
	X	    i = index;
	X	    index = range_end;
	X	    range_end = i;
	X	}
	X    }
	X    if (index < 0 || range_end >= cur_size)
	X	return;
	X    cur_entry = index;
	X    cur_range_end = range_end;
	X    
	X    DrawPalette(cur_size);
	X
	X    if (cur_entry == cur_range_end) {
	X	(void) sprintf(buf, "%d", cur_entry);
	X	if (cur_size > 2)
	X	    HighlightSwatch(cur_entry, cur_size-1);
	X    }
	X    else {
	X	BoxSwatches(cur_entry, cur_range_end);
	X	(void) sprintf(buf, "%d..%d", cur_entry, cur_range_end);
	X    }
	X    panel_set_value(cur_color_item, buf);
	X
	X    for (i= -1; ++i<3;) {
	X	avgP = FALSE;
	X	ptr = (unsigned char **) panel_get(sliders[i], PANEL_CLIENT_DATA);
	X	for (val = 0, j = cur_entry, prev = ((*ptr)[cur_entry]);
	X	     j <= cur_range_end; j++) {
	X	    avgP = (avgP | (prev != ((*ptr)[j])));
	X	    val += (prev = (*ptr)[j]);
	X	}
	X	panel_set(sliders[i], PANEL_VALUE, val/(cur_range_end-cur_entry+1), 0);
	X	panel_set(avg_markers[i], PANEL_SHOW_ITEM, avgP, 0);
	X	avg_existsP = (avg_existsP | avgP);
	X    }
	X    Message((avg_existsP ? "* Starred items represent averages." : ""), 0);
	X}
	X
	X
	X
	X/* 
	X * slider_notify - When the user clicks on a slider, update the colormap,
	X *                 the colormap array, and hide the slider's asterisk 
	X *                 item (in case it's on).
	X */
	X    
	Xstatic void slider_notify(slider, value, event)
	XPanel_item slider;
	Xint value;
	XEvent *event;
	X{
	X    void UpdateColorMaps();
	X    unsigned char **ptr;
	X    int i;
	X
	X    ptr = (unsigned char **) panel_get(slider, PANEL_CLIENT_DATA);
	X    for (i=cur_entry; i <= cur_range_end; ++i)
	X	(*ptr)[i] = (unsigned char) value;
	X
	X    UpdateColorMaps(U_NEW_COLOR);
	X    panel_set((Panel_item)panel_get(slider, PANEL_NEXT_ITEM),
	X	      PANEL_SHOW_ITEM, FALSE, 0);
	X}
	X
	X
	X/* 
	X * ArrowEvent - When the user clicks on an arrow, update its slider, 
	X *              increment the current color(s) (possibly by a linearly 
	X *              increasing amount), update the array and the colormap, 
	X *              and possibly turn off the color's asterisk (if all the 
	X *              colors in the range have become equal).
	X */
	X
	Xstatic void ArrowEvent(button, event)
	XPanel_item button;
	XEvent *event;
	X{
	X    extern int atoi();
	X    int i, prev, new_val, total = 0;
	X    boolean avgP = FALSE;
	X    boolean proportional = (boolean) panel_get_value(proportional_item);
	X    int step_size = atoi(panel_get_value(step_size_item));
	X    Panel_item my_slider = panel_get(button, PANEL_CLIENT_DATA);
	X    unsigned char **ptr;
	X
	X    if ((Pixrect *)panel_get(button, PANEL_LABEL_IMAGE) == &left_arrow)
	X	step_size = -step_size;
	X
	X    ptr = (unsigned char **) panel_get(my_slider, PANEL_CLIENT_DATA);
	X    for (i = cur_entry, prev = -1; i <= cur_range_end; i++) {
	X	new_val = (*ptr)[i] + (step_size * (proportional ? i-cur_entry+1 : 1));
	X	if (new_val > MAX_BRIGHTNESS)
	X	    new_val = MAX_BRIGHTNESS;
	X	else if (new_val < 0)
	X	    new_val = 0;
	X	avgP = (avgP | (prev == -1 ? FALSE : (prev != new_val)));
	X	total += ((*ptr)[i] = prev = new_val);
	X    }
	X    UpdateColorMaps(U_NEW_COLOR);
	X    panel_set(my_slider, PANEL_VALUE, total/(cur_range_end-cur_entry+1), 0);
	X    panel_set((Panel_item)panel_get(my_slider, PANEL_NEXT_ITEM),
	X	      PANEL_SHOW_ITEM, avgP, 0);
	X}
	X
	X
	X
	X/* 
	X * Copy - Copy the current range onto the clipboard.
	X */
	X
	Xstatic void Copy()
	X{
	X    void UpdateColorMaps();
	X    int nbytes;
	X
	X    clipboard_entries = 1+(cur_range_end-cur_entry);
	X    nbytes = sizeof(unsigned char)*clipboard_entries;
	X    bcopy((char *) cur_map.cm_red + cur_entry, 
	X	  (char *) clipboard.cm_red, nbytes);
	X    bcopy((char *) cur_map.cm_green + cur_entry, 
	X	  (char *) clipboard.cm_green, nbytes);
	X    bcopy((char *) cur_map.cm_blue + cur_entry, 
	X	  (char *) clipboard.cm_blue, nbytes);
	X}
	X
	X
	X/* 
	X * Paste - Paste the clipboard contents onto the current CMS starting at 
	X *         the current entry.
	X */
	X
	Xstatic void Paste()
	X{
	X    void UpdateColorMaps();
	X
	X    int nbytes = sizeof(unsigned char) *
	X	(clipboard_entries + cur_entry > cur_size ? 
	X	 cur_size - cur_entry : clipboard_entries);
	X					
	X    bcopy((char *) clipboard.cm_red, (char *) cur_map.cm_red + cur_entry, 
	X	  nbytes);
	X    bcopy((char *) clipboard.cm_green, (char *) cur_map.cm_green + cur_entry, 
	X	  nbytes);
	X    bcopy((char *) clipboard.cm_blue, (char *) cur_map.cm_blue + cur_entry, 
	X	  nbytes);
	X    UpdateColorMaps(U_NEW_COLOR);
	X    SelectEntry(cur_entry, cur_range_end);
	X    if (clipboard_entries > (nbytes / sizeof(unsigned char)))
	X	Message("<Only the first %d clipboard items fit.>", 
	X		(nbytes / sizeof(unsigned char)));
	X}
	X
	X
	X
	X/* 
	X * KeyEvent - Take the appropriate action when the user types a key.  
	X *            Note that ascii input from all three windows are directed 
	X *            to the control_panel.
	X *               All that crap with esp_seq is necessary because you 
	X *            can't get KEY_RIGHT() events for the arrow keys.  (At 
	X *            least not on my Sun3/160.)  So this routine looks for a 
	X *            consecutive <Esc>[n, where "n" is D or C.
	X */
	X
	Xstatic void KeyEvent(win, event, arg)
	XWindow win;
	XEvent *event;
	Xcaddr_t arg;
	X{
	X    void SelectEntry();
	X    void Quit();
	X
	X    static short esq_seq = 0;
	X
	X    if (esq_seq == 2)
	X	switch (event_id(event)) {
	X	  case 'D':
	X	    event_set_id(event, '<');
	X	    break;
	X	  case 'C':
	X	    event_set_id(event, '>');
	X	    break;
	X	}
	X	
	X    switch(event_id(event)) {
	X      case '\033':
	X	esq_seq = 1;
	X	break;
	X      case '[':
	X	if (esq_seq == 1)
	X	    esq_seq = 2;
	X	break;
	X      case '<':
	X	SelectEntry(cur_entry-1, -1);
	X	esq_seq = 0;
	X	break;
	X      case '>':
	X	SelectEntry(cur_entry+1, -1);
	X	esq_seq = 0;
	X	break;
	X      case '\003':
	X	Quit();
	X      default:
	X	esq_seq = 0;
	X	window_default_event_proc(win, event, arg);
	X	break;
	X	
	X    }
	X}
	X
	X
	X/* 
	X * KeyedEntry - Preprocess keyboard input to the Current Color item.  
	X *              Only allow digits and periods to be entered.  When 
	X *              Return is pressed, parse the text for the starting and 
	X *              ending values of the new range.  If no starting or ending
	X *              range is found, assume zero and the highest value in the 
	X *              current colormap, respectively.
	X */
	X
	Xstatic Panel_setting 
	XKeyedEntry(item, event)
	XPanel_item item;
	XEvent *event;
	X{
	X    extern int atoi();
	X    void SelectEntry();
	X    int t1, t2;
	X    boolean error_flag = false;
	X    char *s, *ptr;
	X
	X    if (event_id(event)=='\r' || event_id(event)=='\n') {
	X	if (ptr = rindex(s = panel_get_value(item), '.')) {
	X	    if (*++ptr == '\0')
	X		t1 = cur_size-1;
	X	    else
	X		t1 = atoi(ptr);
	X	    if (t1 >= cur_size || (t2 = atoi(s)) > cur_size)
	X		error_flag = true;
	X	    else
	X		SelectEntry(t2, t1);
	X	}
	X	else if ((t1 = atoi(panel_get_value(item))) < cur_size)
	X	    SelectEntry(atoi(panel_get_value(item)), -1);
	X	else
	X	    error_flag = true;
	X
	X	if (error_flag)
	X	    Message("<Valid colors for this cms are 0..%d>", cur_size-1);
	X    }
	X    else if (iscntrl(event_id(event)) || isdigit(event_id(event)) ||
	X	     event_id(event) == '.')
	X	return(panel_text_notify(item, event));
	X
	X    return(PANEL_NONE);
	X}
	X
	X
	X/* 
	X * NumericText - Notify procedure for a text item that only wants 
	X *               digits in itself.
	X */
	X
	Xstatic Panel_setting 
	XNumericText(item, event)
	XPanel_item item;
	XEvent *event;
	X{
	X    return ((isdigit(event_id(event)) || iscntrl(event_id(event))) ?
	X	    panel_text_notify(item, event) : PANEL_NONE);
	X}
	X
	X
	X	
	X
	X/*
	X *  UpdateColorMaps - Sets the colormap of the four local windows 
	X *                    acccording to the value of use_colormap.  The 
	X *                    amount of action required is determined by the 
	X *                    type parameter and the current state of the 
	X *                    use_colormap variable.
	X *       
	X *            U_NEW_COLOR - simply updates the window manager's record 
	X *                          of the current CMS to match Palette's.
	X *            U_NEW_CMS -   tells the window manager to assign a new 
	X *                          colormap to Palette's canvas window, or to 
	X *                          all its windows if use_colormap is true.
	X *            U_NEW_STATE - Sets the colormaps of the other (non-canvas) 
	X *                          windows when the "Palette's Colormap" feature
	X *                          gets toggled.  Forces the wm to redraw the
	X *                          windows too.
	X */
	X
	Xstatic void UpdateColorMaps(type)
	Xenum updatecolor_msg type;
	X{
	X    int i, win_limit;
	X    char *name;
	X
	X    name = cur_name;
	X    win_limit = ((type == U_NEW_STATE || use_colormap) ? NUM_MY_WINDOWS : 1);
	X    for (i = (type==U_NEW_STATE? 0 : -1); ++i < win_limit;) {
	X	if (i == 1 && !use_colormap)
	X	    name = frame_cms_name;
	X	if (i == 2 && !use_colormap)
	X	    name = subwins_cms_name;
	X
	X	if (type != U_NEW_COLOR)
	X	    pw_setcmsname(my_pixies[i], name);
	X
	X	if (i==0 || use_colormap)
	X	    pw_putcolormap(my_pixies[i], 0, cur_size, 
	X			   cur_map.cm_red, cur_map.cm_green, cur_map.cm_blue);
	X    }
	X    if (type == U_NEW_STATE || (type == U_NEW_CMS && use_colormap)) {
	X	wmgr_refreshwindow(my_frame_fd);
	X	if (cur_size > 4 && cur_size < MAX_COLORS && use_colormap)
	X	    window_set(frame, FRAME_ICON, color_icon, 0);
	X	else
	X	    window_set(frame, FRAME_ICON, &mono_icon, 0);
	X    }
	X}
	X
	X
	X/* 
	X * UseColorMap - Change state of the Palette's Colormap feature, and 
	X *               update the windows as appropriate.
	X *               
	X *               See BorrowFramesCMS for explanation of the conditional 
	X *               statments.
	X */
	X
	Xstatic void UseColorMap(item, value, event)
	XPanel_item item;
	Xint value;
	XEvent *event;
	X{
	X    void UpdateColorMaps(), BorrowFramesCMS(), SelectCMS();
	X    char *glob_name = cur_name;
	X    
	X    if (value == false)
	X	BorrowFramesCMS();
	X
	X    use_colormap = value;
	X    UpdateColorMaps(U_NEW_STATE);
	X
	X    if (value == false)
	X	SelectCMS(glob_name);
	X}
	X
	X
	X
	X/* 
	X * WalkDepth
	X */
	X
	Xstatic void WalkDepth(item, value, event)
	XPanel_item item;
	Xint value;
	XEvent *event;
	X{
	X    shallow_walkP = (boolean) value;
	X}
	X
	X
	X
	X/* 
	X * CreateNewMap - Enter a new map in the colormap table.
	X */
	X
	Xstatic void CreateNewMap()
	X{
	X    extern char *malloc();
	X    extern int getpid();
	X    boolean MakeCMS();
	X    static int gensym = 0;
	X    static struct colormapseg data; /* static so cur_name can point to it. */
	X    int i;
	X
	X    (void) sprintf(data.cms_name, "Palette%d-%d", getpid(), ++gensym);
	X    data.cms_size = 1<<((int)panel_get_value(new_map_size)+1);
	X
	X    cur_map.cm_red = (unsigned char *) malloc((unsigned) data.cms_size);
	X    cur_map.cm_green = (unsigned char *) malloc((unsigned) data.cms_size);
	X    cur_map.cm_blue = (unsigned char *) malloc((unsigned) data.cms_size);
	X    for (i = -1; ++i < data.cms_size;)
	X	cur_map.cm_red[i] = cur_map.cm_green[i] = cur_map.cm_blue[i] =
	X	    i*(255/(data.cms_size-1.0));
	X
	X    if (MakeCMS(&data, &cur_map)) {
	X	panel_paint(table_panel, PANEL_NO_CLEAR);
	X	SelectCMS(data.cms_name);
	X    }
	X    else
	X	Message("<Error: CMS table full.  Try \"Reread Maps\".>", 0);
	X}
	X
	X
	X    
	X
	X/* 
	X * Save - Save the current colormap in the specified file, in one of the
	X *        three specified formats.
	X */
	X
	Xstatic void Save()
	X{
	X    FILE *fp;
	X    int i;
	X    char *name;
	X    char buf[180];
	X    boolean error = false;
	X    /* RGB array */
	X    int c;
	X    unsigned char **ptr;
	X
	X    /* Rasterfile */
	X    extern int SavePalette();
	X    colormap_t colormap;
	X    Pixrect *null_pr;
	X
	X    if (fp = fopen(name = panel_get_value(file_name), "r")) {
	X	(void) fclose(fp);
	X	(void) sprintf(buf, "The file \"%s\" exists.  Press the left mouse\
	X button to overwrite.  To cancel press the right mouse button.", name);
	X	if (wmgr_confirm(my_frame_fd, buf) == 0) {
	X	    Message("Save operation cancelled.", 0);
	X	    return;
	X	}
	X    }
	X    fp = fopen(panel_get_value(file_name), "w");
	X    if (fp==NULL) {
	X	error = true;
	X	Message("<Error: Couldn't open specified file.>", 0);
	X    }
	X    else {
	X	switch((int)panel_get_value(file_type)) {
	X	  case 0:		/* RGB arrays */
	X	    for (i = -1; ++i<3;) {
	X		switch (i) {
	X		  case 0:
	X		    name = "red";
	X		    ptr = &(cur_map.cm_red);
	X		    break;
	X		  case 1:
	X		    name = "green";
	X		    ptr = &(cur_map.cm_green);
	X		    break;
	X		  case 2:
	X		    name = "blue";
	X		    ptr = &(cur_map.cm_blue);
	X		    break;
	X		}
	X
	X		(void) fprintf(fp, "unsigned char %s[%d] = %*c", name, cur_size,
	X			(2*(i==0)+(i==2)+(cur_size>11)+(cur_size<100)), '{');
	X		for(c = -1; ++c < cur_size;) {
	X		    if ((c%16) == 11)
	X			(void) fprintf(fp, "\n/*%3d*/ ", c );
	X		    (void) fprintf(fp, "%3d%c", (*ptr)[c], 
	X			    (c==cur_size-1 ? '}' : ','));
	X		}
	X		(void) fprintf(fp, ";\n\n");
	X	    }
	X	    break;
	X	  case 1:		/* Number list */
	X	    for (i = -1; ++i < cur_size; )
	X		(void) fprintf(fp, "%3d %3d %3d\n", *(cur_map.cm_red+i), 
	X			       *(cur_map.cm_green+i), *(cur_map.cm_blue+i));
	X	    break;
	X	  case 2:		/* Null rasterfile w/ colormap */
	X	    colormap.type = RMT_EQUAL_RGB;
	X	    colormap.length = cur_size;
	X	    colormap.map[0] = cur_map.cm_red;
	X	    colormap.map[1] = cur_map.cm_green;
	X	    colormap.map[2] = cur_map.cm_blue;
	X
	X	    null_pr = mem_create(0, 0, 8);
	X
	X	    if (pr_dump(null_pr, fp, &colormap, RT_STANDARD, 0))
	X		error = true;
	X	    pr_destroy(null_pr);
	X	    break;
	X	  case 3:		/* Picture of the palette */
	X	    colormap.type = RMT_EQUAL_RGB;
	X	    colormap.length = cur_size;
	X	    colormap.map[0] = cur_map.cm_red;
	X	    colormap.map[1] = cur_map.cm_green;
	X	    colormap.map[2] = cur_map.cm_blue;
	X
	X	    DrawPalette(cur_size);
	X
	X	    if (SavePalette(fp, &colormap))
	X		error = true;
	X
	X	    HighlightSwatch(cur_entry, cur_size-1);
	X	    break;
	X	}
	X	(void) fclose(fp);
	X	if (error)
	X	    Message("<Error occured while writing to file.>", 0);
	X	else
	X	    Message("File written.", 0);
	X    }
	X}
	X
	X/*
	X * Load
	X */
	X
	X/*
	X * Load calls three auxiliary routines.  Each takes an open FILE *
	X * and returns a count of how many colors it read in, or:
	X *     0 to indicate that the file is not of the required type.
	X *    -1 to indicate that it's the right type but an error occurred
	X *       before any loading took place.
	X *    -2 the colormap was partially loaded when an error occurred
	X *       (this is bogus).
	X * The subroutine displays an error message whenever -1 or -2 is returned.
	X */
	X
	Xstatic void Load()
	X{
	X    void UpdateColorMaps();
	X    int Load_NumList(), Load_Rasterfile(), Load_C_Array();
	X
	X    FILE *fp;
	X    int ccount;
	X
	X    if (cur_size == 2)
	X	Message("<Error: Can't load into a 2 color map.>", 0);
	X    if (fp = fopen(panel_get_value(file_name), "r")) {
	X	if ((ccount = Load_NumList(fp)) == 0) {
	X	    rewind(fp);
	X	    if ((ccount = Load_Rasterfile(fp)) == 0) {
	X		rewind(fp);
	X		if ((ccount = Load_C_Array(fp)) == 0)
	X		    Message("<Error: Couldn't find any colors in file.>", 0);
	X	    }
	X	}
	X	if (ccount > 0)
	X	    Message("<Loaded %d color map from file.>", ccount);
	X	if (ccount > 0 || ccount == -2)
	X	    UpdateColorMaps(U_NEW_COLOR);
	X	(void) fclose(fp);
	X    }
	X    else
	X	Message("<Error: Couldn't open specified file>", 0);
	X}
	X
	X
	Xstatic int Load_NumList(fp)
	XFILE *fp;
	X{
	X    int tem1, tem2, tem3;
	X    int i;
	X
	X    for(i = -1; 
	X	    fscanf(fp, "%d %d %d", &tem1, &tem2, &tem3) == 3 &&
	X	    ++i < cur_size; ) {
	X	*(cur_map.cm_red + i) = tem1;
	X	*(cur_map.cm_green + i) = tem2;
	X	*(cur_map.cm_blue + i) = tem3;
	X    }
	X    if (i == cur_size) {
	X	Message("<Error: Only the first %d colors fit.>", i);
	X	return(-2);
	X    }
	X    else
	X	return(i == -1 ? 0 : i+1);
	X}
	X
	X
	Xstatic int Load_Rasterfile(fp)
	XFILE *fp;
	X{
	X    struct rasterfile rh;
	X    colormap_t colormap;
	X    enum {NOT_A_RASTERFILE, DID_GOOD, ERROR} status = ERROR;
	X    boolean isa_rasterfile = true;
	X
	X    if (pr_load_header(fp, &rh) == PIX_ERR)
	X	status = NOT_A_RASTERFILE;
	X    else if (rh.ras_maplength == 0 || rh.ras_maptype == RMT_NONE)
	X	Message("<Error: File's colormap is empty.>", 0);
	X    else if (rh.ras_maptype != RMT_EQUAL_RGB)
	X	Message("<Error: File's colormap not of type RMT_EQUAL_RGB", 0);
	X    else if ((colormap.length = rh.ras_maplength / 3) > cur_size)
	X	Message("<Error: Can't fit %d colors into current map>",
	X		colormap.length);
	X    else {
	X	colormap.type = RMT_EQUAL_RGB;
	X	colormap.map[0] = cur_map.cm_red;
	X	colormap.map[1] = cur_map.cm_green;
	X	colormap.map[2] = cur_map.cm_blue;
	X	/* Note colormap.length set above */
	X	if (pr_load_colormap(fp, &rh, &colormap) == PIX_ERR)
	X	    Message("<Major bummer: Error while reading the colormap.>", 0);
	X	else
	X	    status = DID_GOOD;
	X    }
	X    
	X    return((status==DID_GOOD ? colormap.length :
	X	    (status==NOT_A_RASTERFILE ? 0 : -1)));
	X}
	X
	Xstatic int Load_C_Array(fp)
	XFILE *fp;
	X{
	X    char buf[BUFSIZ];
	X    char *targ, *ptr;
	X    int rgb, ccolor = 0;
	X    boolean in_comment = false;
	X    unsigned char *cur_array;
	X
	X    do {
	X	do {
	X	    if (ptr = fgets(buf, BUFSIZ, fp))
	X		for (targ = "char red[", ptr = buf; *targ && *ptr; )
	X		    if (*ptr++ == *targ)
	X			++targ;
	X	} while (ptr && (*targ != '\0'));
	X    } while (ptr && !index(ptr, '='));
	X    
	X    if (ptr) {			/* Hey, we found our target! */
	X	for (rgb = -1; ++rgb < 3; ) {
	X	    ccolor = 0;
	X	    cur_array = (rgb == 0 ? cur_map.cm_red :
	X			 (rgb == 1 ? cur_map.cm_green :
	X			  cur_map.cm_blue));
	X	    while (*ptr != '{')
	X		if (*ptr == '\0') {
	X		    ptr = fgets(buf, BUFSIZ, fp);
	X		    if (ptr == NULL) {
	X			Message("<Error: EOF in color array.>", 0);
	X			return(rgb == 0 ? -1 : -2);
	X		    }
	X		}
	X		else
	X		    ++ptr;
	X
	X	    if (*ptr) {		/* Found the open brace. */
	X		while (1) {
	X		    /* Get a new line when you finish one */
	X		    if (*ptr == '\0') {
	X			ptr = fgets(buf, BUFSIZ, fp);
	X			if (ptr == NULL) {
	X			    Message("<Error: EOF in color array.>", 0);
	X			    return(-2);
	X			}
	X		    }
	X		    if (*ptr == '}')
	X			break;
	X
	X		    /* Look for comments */
	X		    if (*ptr == '/' && *(ptr+1) == '*')
	X			in_comment = true;
	X		    if (*ptr == '*' && *(ptr+1) == '/')
	X			in_comment = false;
	X		    
	X		    /* This is a number, read it */
	X		    if (!in_comment && isdigit(*ptr)) {
	X			*(cur_array + ccolor++) = atoi(ptr);
	X			while (isdigit(*++ptr))
	X			    ;
	X		    }
	X		    else
	X			++ptr;
	X		}
	X	    }
	X	}
	X    }
	X    return(ccolor);
	X}
	X
	X
	X
	X/* 
	X * Quit
	X */
	X
	Xstatic void Quit()
	X{
	X    exit(0);
	X}
	X
	X
	X/* 
	X * Reread_Maps - Do a brute force reread of the colormaps.  Delete 
	X *               everything in the hash table and the table_panel.  Then 
	X *               walk down the tree the same as at startup (except this 
	X *               time, our windows are in the tree).
	X */
	X
	Xstatic void Reread_Maps(item, event)
	XPanel_item item;
	XEvent *event;
	X{
	X    int Get_Root();
	X    boolean WalkWinTree();
	X    void SelectCMS();
	X    char *item_name;
	X    int rootfd;
	X    
	X    if (panel_get_value(reset_on_reread)==0) {
	X	panel_each_item(table_panel, item)
	X	    item_name = (char *) panel_get(item, PANEL_LABEL_STRING);
	X	*(rindex(item_name, '[')-1) = '\0';
	X	H_Delete(item_name);
	X	panel_destroy_item(item);
	X	panel_end_each
	X	}
	X    if ((rootfd=Get_Root(control_panel))==-1)
	X	Message("<Error: Couldn't open root window device.>", 0);
	X    else {
	X	if (!WalkWinTree(rootfd, shallow_walkP))
	X	    Message("<Error: CMS table full.  Not all windows processed.>", 0);
	X	(void) close(rootfd);
	X	if (H_Member(cur_name, NIL(struct cms_map), NIL(Panel_item *)))
	X	    item_name = cur_name;
	X	else
	X	    item_name = frame_cms_name;
	X	
	X	cur_name = NULL;
	X	SelectCMS(item_name);
	X	panel_paint(table_panel, PANEL_CLEAR);
	X    }
	X}
	X
	X
	X/* 
	X * MakeCMS - Create a new entry as specified by the two params and 
	X *           return true if it doesn't already exist.  Otherwise, do 
	X *           nothing and return false.
	X */
	X
	Xboolean MakeCMS(cmsdata, themap)
	Xstruct colormapseg *cmsdata;
	Xstruct cms_map *themap;
	X{
	X    char buf[CMS_NAMESIZE+6];
	X    char *ptr;
	X    Panel_item item;
	X
	X    (void) sprintf(buf, "%s [%d]", cmsdata->cms_name, cmsdata->cms_size);
	X    
	X    for (ptr=buf+strlen(buf); ptr < buf+CMS_NAMESIZE+6-5; ++ptr)
	X	*ptr = ' ';
	X    *ptr = '\0';
	X
	X    item = panel_create_item(table_panel, PANEL_MESSAGE,
	X			     PANEL_LABEL_STRING, buf,
	X			     0);
	X    if (H_Insert(cmsdata->cms_name, cmsdata->cms_size, item, themap)==false) {
	X	panel_destroy_item(item);
	X	return(false);
	X    }
	X    else
	X	return(true);
	X}
	X
	X
	X/* 
	X * ClickOnCMS - Find out which colormap name was clicked on and make it 
	X *              the current color.
	X *              If it was shift-clicked, delete it from the table.
	X */
	X
	Xstatic void ClickOnCMS(item, event)
	XPanel_item item;
	XEvent *event;
	X{
	X    void SelectCMS();
	X    static char buf[CMS_NAMESIZE+6]; /* static so cur_name can point to it. */
	X
	X    if (event_id(event) == MS_LEFT && event_is_down(event)) {
	X	(void) strcpy(buf, panel_get(item, PANEL_LABEL_STRING));
	X	*(rindex(buf, '[')-1) = '\0';
	X	if (event_shift_is_down(event)) {
	X	    if (!strcmp(buf, frame_cms_name))
	X		Message("<Error: Can't delete Palette's colormap>", 0);
	X	    else {
	X		Message("", 0);
	X		if (item == cur_cms_item)
	X		    SelectCMS(frame_cms_name);
	X		H_Delete(buf);
	X		panel_destroy_item(item);
	X		panel_paint(table_panel, PANEL_CLEAR);
	X	    }
	X	}
	X	else
	X	    SelectCMS(buf);
	X    }
	X}
	X
	X
	X/* 
	X * ResizeCanvas - Call the canvas.c package routine when the canvas size 
	X *                changes.  Then redraw the palette.  Also if necessary, 
	X *                call the routine which defends against a window system 
	X *                bug.  See BorrowFramesCMS() for details.
	X */
	X
	Xstatic void ResizeCanvas()
	X{
	X    extern void SetPaletteSize();
	X    void BorrowFramesCMS();
	X    boolean glob_use = use_colormap;
	X    char *glob_name = cur_name;
	X
	X    SetPaletteSize();
	X    use_colormap = false;	/* So Palette's other win's don't redraw, too */
	X    if (cur_size > 2)
	X	BorrowFramesCMS();
	X    SelectCMS(glob_name);
	X    use_colormap = glob_use;
	X}
	X
	X
	X    
	X/* 
	X * CanvasEvent - Do the right thing with the variety of left- and 
	X *               right-clicks, and drags.
	X */
	X
	Xstatic void CanvasEvent(win, event, arg)
	XWindow win;
	XEvent *event;
	Xcaddr_t arg;
	X{
	X    extern void DrawPalette(), BoxSwatches();
	X    extern int WhichSwatch();
	X    void SelectEntry();
	X    int selection;
	X
	X    if (event_id(event) == LOC_DRAG || event_is_button(event)) {
	X	selection = WhichSwatch(event_x(event), event_y(event));
	X	if (selection < 0)  /* Clicking outside the rect erases the selection */
	X	    DrawPalette(cur_size);
	X	else if (selection != cur_range_end && selection != cur_entry &&
	X		 ((event_id(event) == MS_MIDDLE && event_is_down(event)) ||
	X		  (event_id(event) == MS_LEFT && event_is_up(event)) ||
	X		  event_id(event) == LOC_DRAG))
	X	    SelectEntry(cur_entry, selection);
	X	else if (event_id(event) == MS_LEFT && event_is_down(event)) {
	X	    SelectEntry(selection, -1);
	X	}
	X    }
	X}
	X
	X
	X/* 
	X * SelectCMS - Get the specs for a colormap, and make it the current one. 
	X *             Note, that there should never be an error, since if a map 
	X *             isn't in the table, the user should have no way to get it 
	X *             to here.
	X */
	X
	Xstatic void SelectCMS(name)
	Xchar *name;
	X{
	X    extern void DrawPalette();
	X    void UpdateColorMaps();
	X
	X    int size;
	X
	X    if (cur_name)
	X	panel_set(cur_cms_item, PANEL_LABEL_BOLD, FALSE, 0);
	X    if (size = H_Member(name, &cur_map, &cur_cms_item)) {
	X	cur_size = size;
	X	cur_name = name;
	X	panel_set(cur_cms_item, PANEL_LABEL_BOLD, TRUE, 0);
	X	UpdateColorMaps(U_NEW_CMS);
	X	SelectEntry(cur_entry >= cur_size ? 0 : cur_entry,
	X		   cur_range_end >= cur_size ? -1 : cur_range_end);
	X    }
	X    else
	X	Message("<Weird error: Colormap not in hash table.>", 0);
	X}
	X
	X
	X
	X
	X/* 
	X * BorrowFramesCMS - SunOS 3.4 apparently gets troubled by deep 
	X *                   pixrects and by changes made to a retained pixwin 
	X *                   behind its back.  Specifically, when a canvas gets 
	X *                   resized, the backing pixrect (pw_prretained) gets
	X *                   set to a depth of 1 even for 8 bit deep pixwins.
	X *                   If a color window gets set back to its original 
	X *                   color, the scrollbar color gets messed up.  Also, 
	X *                   when changing a window's icon from an 8-bit to a 
	X *                   one bit, two WINGETCMS ioctl errors are generated.
	X *                   
	X *                   This routine protects against that by allowing 
	X *                   callers to borrow the frame's original colormap 
	X *                   before doing any the above operations.  It's a 
	X *                   nasty kludge, and a lousy description of the 
	X *                   problem.  But, hey, get outta my face.
	X */
	X
	Xstatic void BorrowFramesCMS()
	X{
	X    void SelectCMS();
	X
	X    int glob_entry = cur_entry;
	X    int glob_range_end = cur_range_end;
	X
	X    SelectCMS(frame_cms_name);
	X    cur_entry = glob_entry;	/* In case it was reset to 0 in SelectCMS() */
	X    cur_range_end = glob_range_end;
	X}
	X
SHAR_EOF
if test 38447 -ne "`wc -c < 'palette.c'`"
then
	echo shar: error transmitting "'palette.c'" '(should have been 38447 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'palette.l'" '(8048 characters)'
if test -f 'palette.l'
then
	echo shar: will not over-write existing file "'palette.l'"
else
sed 's/^	X//' << \SHAR_EOF > 'palette.l'
	X.TH palette 1L "8 April 1989" " " " "
	X
	X.SH NAME
	Xpalette \- edit colormaps 
	X.\"
	X.SH SYNOPSIS
	X.B palette
	X[
	X.B \-f
	X]
	X[
	X.B \-s
	X]
	X[
	X.I <SunView window options>
	X]
	X.\"
	X.SH DESCRIPTION
	X.\"  .I name
	X.\"      ...
	X.\" .IR reference (1)
	X.\"
	X.I Palette
	Xis a colormap editing tool.  It can modify the colormaps being used by
	Xother Suntools windows, or create new colormaps.  Colormaps may be saved
	Xto or loaded from C source files, a numeric list or raster files.
	X
	XAs a development tool,
	X.I palette
	Xcan be used to modify a running application's colormap arrays, thus
	Xeliminating the need to make incremental changes to the code, with
	Xtime-consuming recompilations between each modification.  As a graphics
	Xtool,
	X.I palette
	Xcan be used in conjunction with commercial applications or bitmap
	Xeditors such as
	X.IR touchup (l)
	Xwhich have little or no colormap modification abilities.
	X
	XThe tool consists of three windows: a color palette, a colormap table,
	Xand a control panel.
	X
	XThe palette contains a color swatch for each entry in the current
	Xcolormap.  Left-clicking on a swatch makes it the current color.
	XSimilarly, a series of entries may be selected by left-dragging through
	Xthem, or by left- and middle-clicking to specify the bounds of the
	Xregion.
	X
	XThe colormap table lists all the colormaps that 
	X.I palette
	Xcurrently knows about.  The current colormap is displayed in bold.
	XLeft-clicking on one makes it the current colormap.  Shift-left-clicking
	Xdeletes the map from the table.
	X
	XThe control panel contains the instruments for manipulating the current
	Xcolormap.  The panel breaks down into roughly four areas of
	Xfunctionality, as described below.
	X
	X.B "Modifying The Current Color(s)"
	X.RS
	XAt the top are three slider controls for specifying the red, green and
	Xblue components of the current color(s).  If more than one color entry
	Xis selected\(emand the values of a component differ across the
	Xentries\(emthen the slider will indicate the average value for the
	Xcomponent.
	X
	XTo the right of each slider are two arrow buttons.  These allow the user
	Xto step the corresponding red, green or blue component up or down.  The
	Xsize of the step is indicated by the user-modifiable
	X.B Step Size
	Xitem.  When a range of colors is selected, setting the 
	X.B Uniform Steps
	Xitem to
	X.I No
	Xwill cause the arrow buttons to have a linearly increasing effect on
	Xeach entry.  For example, if entries 3 through 5 are selected and the
	Xstep size is 10, then clicking the right arrow would increase entry
	Xthree by 10, entry four by 20 and entry five by 30.  This feature allows
	Xthe user to quickly and easily create complex color schemes.
	X
	XBelow the slider controls, a 
	X.B Current Color
	Xdisplay indicates the positional number of the current color.  As
	Xdescribed above, the current color may be selected by clicking on its
	Xswatch in the palette window.  Alternatively, a number may be typed into
	Xthe
	X.B Current Color
	Xdisplay followed by a Return.  A range may be specified by entering two
	Xnumbers separated by periods.
	X
	XThe
	X.B Copy
	Xbutton copies the selected color(s) onto the "clipboard."  
	X.B Paste
	Xplaces the contents of the clipboard onto the palette starting at the
	Xcurrent entry.
	X.RE
	X
	X.B Creating and Reading Colormaps
	X.RS
	XThe
	X.B New Map
	Xbutton creates a new colormap for editing.  The size of the new map is
	Xspecified by the value of the
	X.B New Map Size
	Xcontrol.
	X
	XWhen
	X.I palette
	Xstarts up, it checks the windows on the screen and enters their
	Xcolormaps into the colormap table.  If new windows are created, or
	Xexisting ones go away,
	X.IR palette 's
	Xstate can be updated by pressing the
	X.B Reread Maps
	Xbutton.  If the
	X.B Read From
	Xitem is set to
	X.IR "All windows" ,
	Xthen every window on the screen will be examined for colormaps.  If it's
	Xset to
	X.IR "Top level frames" ,
	Xthen only the main frames will be examined.  The
	X.B On Reread
	Xoption specifies whether the colormap table should be reset before
	Xrereading the colormaps.  Note that colormaps created by the
	X.B New Map
	Xbutton are not associated with any window (unless it is the current
	Xcolormap, in which case it is being used by the palette window).  This
	Xmeans that if the table is reset when
	X.B On Reread
	Xis set to 
	X.IR "Reset table first" ,
	Xthese new maps will be lost.
	X.RE
	X
	X.B Saving Colormaps
	X.RS
	XThe current colormap may be written to disk in four different formats,
	Xas specified by the
	X.B Save Type
	Xcontrol.  The
	X.I RGB arrays
	Xformat creates C code specifying the numeric values for red, green and
	Xblue arrays.  This output can be incorporated into a C program which can
	Xthen use the SunView procedures for specifying colormaps.  The
	X.I RGB list 
	Xformat creates a text file with the three component values of each color
	Xon a separate line.  (This allows
	X.I palette
	Xto exchange files with a certain inferior colormap program bearing a
	Xsimilar name.)  The 
	X.I Clear raster file
	Xformat creates a raster file containing the current colormap and a blank
	Ximage.  The
	X.I Raster File with palette
	Xformat does the same thing, except the image is a picture of the palette
	Xwindow.  In all four cases, the file name is specified by the
	X.B File Name
	Xitem.
	X.RE
	X
	X.B Loading Colormaps
	X.RS
	XThe 
	X.B Load
	Xbutton reads colormap information into the current colormap from the
	Xfile specified by the 
	X.B File Name
	Xitem.  All four file formats are supported.  The type of the file will
	Xbe determined from its contents.  
	X.I Palette
	Xonly promises to read RGB array files which it created.  But, in fact,
	Xit does quite well at reading array information which is deeply buried
	Xin a C source file regardless of how bizarre the formatting is.  (It
	Xscans through the file looking for the string "char red[".  If it can
	Xfind this in your source file, then it will most likely be able to read
	Xthe data.)
	X.RE
	X
	X.B Program Control
	X.RS
	XIf
	X.B Palette's Colormap
	Xis set to
	X.I Its own
	Xthe control panel and the colormap table will use their own default
	Xcolors (usually, the monochrome colormap).  If this control is set to
	X.IR Selected ,
	Xthen it will use the current colormap.  This is convenient when editing
	Xlarge colormaps which would otherwise be swapped out by the window
	Xsystem when the cursor is outside of the palette window.  On the other
	Xhand, if the foreground and background colors of the current map are
	Xvery similar, it will make it difficult to see the controls.
	X
	XThe
	X.B Quit
	Xbutton exits
	X.I palette.
	X.RE
	X.\"  
	X.SH OPTIONS
	X.TP
	X.B \-f
	XOn startup, 
	X.I palette
	Xnormally looks for colormaps in all windows.  This options says to look
	Xat top level frames only.  (See 
	X.B Read From
	Xcontrol, above.)
	X.TP
	X.B \-s
	XNormally, the windows of the
	X.I palette
	Xtool use their default colormap on startup.  This option causes them to
	Xuse the currently selected colormap.  (See
	X.B Palette's Colormap
	Xcontrol, above.)
	X.\"  
	X.SH USAGE NOTES
	XThe left and right arrow keys (as well as the greater-than and less-than
	Xkeys) select the successive or previous color entry, respectively.
	XControl-C will exit
	X.IR palette .
	X
	XGreat pains were taken to ensure that the windows could be resized
	Xwithout confusing the program.  So if you want smaller or larger
	Xwindows, simply resize it in the standard SunView way.
	X
	XUsers should remember that the background and foreground colors are
	Xdefined as the first and last entries in a colormap, respectively.  The
	XSunView window system prevents the user from setting these to exactly
	Xthe same color.  If this is attempted they will appear as black and
	Xwhite.
	X
	XWhen the current colormap contains between eight and 128 colors, and
	X.B Palette's Colormap
	Xis set to
	X.IR Selected ,
	X.IR palette 's 
	Xicon will appear in color.
	X
	XTwo popular graphics display programs, 
	X.IR screenload (1)
	Xand
	X.IR touchup (l)
	Xdo their own evil deeds to colormaps.  This is of interest to those
	Xusing 
	X.I palette
	Xin conjunction with either of these.
	X.IR screenload (1)
	Xdoesn't load the map if it only has two colors in it.
	X.IR touchup (l)
	Xmakes sure that
	Xthe zeroth and 254th entries in its colormap stay white, and the first
	Xand 255th stay black.
	X.SH AUTHOR
	XWayne Mesard, mesard@BBN.COM
	X.SH "SEE ALSO"
	Xscreenload(1), touchup(l),
	X.I SunView Programmer's Guide
	X
SHAR_EOF
if test 8048 -ne "`wc -c < 'palette.l'`"
then
	echo shar: error transmitting "'palette.l'" '(should have been 8048 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'patchlevel.h'" '(67 characters)'
if test -f 'patchlevel.h'
then
	echo shar: will not over-write existing file "'patchlevel.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'patchlevel.h'
	X#define VERSION_STRING "Palette Version 1.1"
	X#define PATCHLEVEL 0
	X
SHAR_EOF
if test 67 -ne "`wc -c < 'patchlevel.h'`"
then
	echo shar: error transmitting "'patchlevel.h'" '(should have been 67 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'wsm_types.h'" '(632 characters)'
if test -f 'wsm_types.h'
then
	echo shar: will not over-write existing file "'wsm_types.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'wsm_types.h'
	X#ifndef wsm_types_DEFINED
	X#define wsm_types_DEFINED
	X/**
	X ** ADT: LIFO queue of int's
	X **/
	X
	X#ifndef LIFO_Q_SIZE
	X#define LIFO_Q_SIZE 20
	X#endif
	X
	Xtypedef struct {
	X  int q[LIFO_Q_SIZE];
	X  int ptr;
	X} lifo;
	X
	X#define Q_init(QQ) QQ.ptr = 0
	X#define Q_pop(QQ) QQ.q[(--QQ.ptr)]
	X#define Q_peek(QQ) QQ.q[(QQ.ptr-1)]
	X#define Q_push(QQ, DATA) QQ.q[QQ.ptr]=DATA, QQ.ptr=((QQ.ptr+1)%LIFO_Q_SIZE)
	X#define Q_size(QQ) QQ.ptr
	X
	X
	X
	X/**
	X ** ADT: boolean
	X **/
	X
	X#define boolean	short
	X#define false	(short) 0
	X#define true	(short) !false
	X
	X
	X/**
	X ** Typed NULL constant.  To avoid abuse of 0 and NULL.
	X **/
	X
	X#define NIL(type) (type *) 0
	X
	X#endif wsm_types_DEFINED
	X
SHAR_EOF
if test 632 -ne "`wc -c < 'wsm_types.h'`"
then
	echo shar: error transmitting "'wsm_types.h'" '(should have been 632 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0