home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / dos / fraktale / frasr192.exe / EDITPAL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-25  |  82.9 KB  |  3,504 lines

  1. /*
  2.  * editpal.c
  3.  *
  4.  * Edits VGA 256-color palettes.
  5.  *
  6.  * Key to initials:
  7.  *
  8.  *    EAN - Ethan Nagel [70022,2552]
  9.  *
  10.  *    JJB - Juan J. Buhler [jbuhler@gidef.edu.ar]
  11.  *
  12.  *    TIW - Tim Wegner
  13.  *
  14.  * Revision History:
  15.  *
  16.  *   10-22-90 EAN     Initial release.
  17.  *
  18.  *   10-23-90 EAN     "Discovered" get_line/put_line functions, integrated
  19.  *                them in (instead of only getcolor/putcolor). Much
  20.  *                faster!
  21.  *              Redesigned color editors (now at top of palette) and
  22.  *                re-assigned some keys.
  23.  *              Added (A)uto option.
  24.  *              Fixed memory allocation problem.  Now uses shared
  25.  *                FRACTINT data area (strlocn).  Uses 6 bytes DS.
  26.  *
  27.  *   10-27-90 EAN     Added save to memory option - will save screen image to
  28.  *                memory, if enough mem avail.  (disk otherwise).
  29.  *              Added s(T)ripe mode - works like (S)hade except only
  30.  *                changes every n'th entry.
  31.  *              Added temporary palette save/restore.  (Can work like
  32.  *                an undo feature.)  Thanks to Pieter Branderhorst for
  33.  *                idea.
  34.  *
  35.  *   10-28-90 EAN     The (H)ide function now makes the palette invisible,
  36.  *                while allowing any other operations (except '\\' -
  37.  *                move/resize) to continue.
  38.  *
  39.  *   10-29-90 PB (in EAN's absence, <grin>)
  40.  *              Change 'c' to 'd' and 's' to '=' for below.
  41.  *              Add 'l' to load palette from .map, 's' to store .map.
  42.  *              Add 'c' to invoke color cycling.
  43.  *              Change cursor to use whatever colors it can from
  44.  *              the palette (not fixed 0 and 255).
  45.  *              Restore colors 0 and 255 to real values whenever
  46.  *              palette is not on display.
  47.  *              Rotate 255 colors instead of 254.
  48.  *              Reduce cursor blink rate.
  49.  *
  50.  *   11-15-90 EAN     Minor "bug" fixes.  Continuous rotation now at a fixed
  51.  *                rate - once every timer tick (18.2 sec);  Blanks out
  52.  *                color samples when rotating; Editors no longer rotate
  53.  *                with the colors in color rotation mode;  Eliminated
  54.  *                (Z)oom mode; other minor fixes.
  55.  *
  56.  *   01-05-91 PB      Add 'w' function to convert to greyscale.
  57.  *
  58.  *   01-16-91 PB      Change rotate function to use new cyclerange stuff.
  59.  *
  60.  *   01-29-91 EAN     Made all colors editable.  The two reserved colors are
  61.  *             X'ed out.  They can be edited but the color is not
  62.  *             visible.  (There is an X over the sample instead.)
  63.  *              Changed default reserved colors to 254 & 255.
  64.  *              Added 'v' command to set the reserved colors to those
  65.  *             under the editors.
  66.  *              Added 'o' command to set the rotate range to between
  67.  *                the two editors.
  68.  *              Modified 'w' function:
  69.  *                uses internal function to do conversion (not BIOS)
  70.  *                will convert only current color if in 'x' mode or
  71.  *              range between editors in 'y' mode or entire palette
  72.  *              if in "normal" mode.
  73.  *
  74.  *   02-08-91 EAN     Improved 16 color support.  In 16 color mode, colors
  75.  *                16-255 have a dot over them and are editable but not
  76.  *                visible (like the two reserved colors).
  77.  *
  78.  *   09-08-91 SWT     Added 'n' command to make a negative color palette:
  79.  *                      will convert only current color if in 'x' mode or
  80.  *                      range between editors in 'y' mode or entire palette
  81.  *                      if in "normal" mode.
  82.  *
  83.  *   03-03-92 JJB     Added '!', '@' and '#' commands to swap RG, GB and
  84.  *                      RB columns (sorry, I didn't find better keys)
  85.  *
  86.  *  10-03-92 TIW      Minor changes for Jiim support, primarily changing
  87.  *                    variables from static to global.
  88.  *
  89.  *   2-11-93 EAN      Added full Undo ('U' key) and Redo ('E' key)
  90.  *                      capability.  Works pretty much as you'd expect
  91.  *                      it to.
  92.  *
  93.  *    3-6-93 EAN      Modified "freestyle" mode, written by RB, to integrate
  94.  *                      into palette editor more completely and work with
  95.  *                      undo logic.
  96.  *                    Added status area under the "fractint" message to
  97.  *                      display current state of editor.  A = Auto mode,
  98.  *                      X, Y = exclusion modes, F = freesyle mode, T = stripe
  99.  *                      mode is waiting for #.
  100.  *
  101.  */
  102.  
  103. #ifdef DEBUG_UNDO
  104. #include "mdisp.h"   /* EAN 930211 *** Debug Only *** */
  105. #endif
  106.  
  107. #include <stdio.h>
  108. #include <stdlib.h>
  109. #include <string.h>
  110. #ifndef XFRACT
  111. #include <stdarg.h>
  112. #include <dos.h>     /* for FP_SEG & FP_OFF */
  113. #else
  114. #include <varargs.h>
  115. #endif
  116. #include <math.h>
  117.  
  118. #ifdef __TURBOC__
  119. #   include <mem.h>   /* to get mem...() declarations */
  120. #endif
  121.  
  122. #include "fractint.h" /* for overlay stuff */
  123. #include "prototyp.h"
  124.  
  125.  
  126. /*
  127.  * misc. #defines
  128.  */
  129.  
  130. #define FONT_DEPTH        8      /* font size */
  131.  
  132. #define CSIZE_MIN        8      /* csize cannot be smaller than this */
  133.  
  134. #define CURSOR_SIZE        5      /* length of one side of the x-hair cursor */
  135.  
  136. #ifndef XFRACT
  137. #define CURSOR_BLINK_RATE   3      /* timer ticks between cursor blinks */
  138. #else
  139. #define CURSOR_BLINK_RATE   300      /* timer ticks between cursor blinks */
  140. #endif
  141.  
  142. #define FAR_RESERVE     8192L      /* amount of far mem we will leave avail. */
  143.  
  144. #define MAX_WIDTH     1024      /* palette editor cannot be wider than this */
  145.  
  146. char scrnfile[] = "FRACTINT.$$1";  /* file where screen portion is */
  147.                    /* stored */
  148. char undofile[] = "FRACTINT.$$2";  /* file where undo list is stored */
  149. #define TITLE   "FRACTINT"
  150.  
  151. #define TITLE_LEN (8)
  152.  
  153.  
  154. #define newx(size)     mem_alloc(size)
  155. #define new(class)     (class *)(mem_alloc(sizeof(class)))
  156. #define delete(block)  block=NULL  /* just for warning */
  157.  
  158. #ifdef XFRACT
  159. int editpal_cursor = 0;
  160. #endif
  161.  
  162.  
  163. /*
  164.  * Stuff from fractint
  165.  */
  166.  
  167. #if 0
  168.  /* declarations moved to PRORTOTYPE.H - this left for docs */
  169.  BYTE dacbox[256][3];             /* DAC spindac() will use         */
  170.  int         sxdots;         /* width of physical screen         */
  171.  int         sydots;         /* depth of physical screen         */
  172.  int         sxoffs;         /* start of logical screen         */
  173.  int         syoffs;         /* start of logical screen         */
  174.  int         lookatmouse;     /* mouse mode for getakey(), etc    */
  175.  int         strlocn[];      /* 10K buffer to store classes in   */
  176.  int         colors;         /* # colors avail.             */
  177.  int         color_bright;     /* brightest color in palette         */
  178.  int         color_dark;     /* darkest color in palette         */
  179.  int         color_medium;     /* nearest to medbright gray color  */
  180.  int         rotate_lo, rotate_hi;
  181.  int         debugflag;
  182. #endif
  183. int using_jiim = 0;
  184.  
  185. /*
  186.  * basic data types
  187.  */
  188.  
  189.  
  190. typedef struct
  191.    {
  192.    BYTE red,
  193.          green,
  194.          blue;
  195.    } PALENTRY;
  196.  
  197.  
  198.  
  199. /*
  200.  * static data
  201.  */
  202.  
  203.  
  204. static BYTE far *font8x8 = NULL;
  205. BYTE     *line_buff;   /* must be alloced!!! */
  206. static BYTE      fg_color,
  207.               bg_color;
  208. static BOOLEAN          reserve_colors;
  209. static BOOLEAN          inverse;
  210.  
  211. static float    gamma_val = 1;
  212.  
  213.  
  214. /*
  215.  * Interface to FRACTINT's graphics stuff
  216.  */
  217.  
  218.  
  219. static void setpal(int pal, int r, int g, int b)
  220.    {
  221.    dacbox[pal][0] = (BYTE)r;
  222.    dacbox[pal][1] = (BYTE)g;
  223.    dacbox[pal][2] = (BYTE)b;
  224.    spindac(0,1);
  225.    }
  226.  
  227.  
  228. static void setpalrange(int first, int how_many, PALENTRY *pal)
  229.    {
  230.    memmove(dacbox+first, pal, how_many*3);
  231.    spindac(0,1);
  232.    }
  233.  
  234.  
  235. static void getpalrange(int first, int how_many, PALENTRY *pal)
  236.    {
  237.    memmove(pal, dacbox+first, how_many*3);
  238.    }
  239.  
  240.  
  241. static void rotatepal(PALENTRY *pal, int dir, int lo, int hi)
  242.    {             /* rotate in either direction */
  243.    PALENTRY hold;
  244.    int        size;
  245.  
  246.    size  = 1 + (hi-lo);
  247.  
  248.    if ( dir > 0 )
  249.       {
  250.       while ( dir-- > 0 )
  251.          {
  252.          memmove(&hold, &pal[hi],  3);
  253.          memmove(&pal[lo+1], &pal[lo], 3*(size-1));
  254.          memmove(&pal[lo], &hold, 3);
  255.          }
  256.       }
  257.  
  258.    else if ( dir < 0 )
  259.       {
  260.       while ( dir++ < 0 )
  261.          {
  262.          memmove(&hold, &pal[lo], 3);
  263.          memmove(&pal[lo], &pal[lo+1], 3*(size-1));
  264.          memmove(&pal[hi], &hold,  3);
  265.          }
  266.       }
  267.    }
  268.  
  269.  
  270. static void clip_put_line(int row, int start, int stop, BYTE *pixels)
  271.    {
  272.    if ( row < 0 || row >= sydots || start > sxdots || stop < 0 )
  273.       return ;
  274.  
  275.    if ( start < 0 )
  276.       {
  277.       pixels += -start;
  278.       start = 0;
  279.       }
  280.  
  281.    if ( stop >= sxdots )
  282.       stop = sxdots - 1;
  283.  
  284.    if ( start > stop )
  285.       return ;
  286.  
  287.    put_line(row, start, stop, pixels);
  288.    }
  289.  
  290.  
  291. static void clip_get_line(int row, int start, int stop, BYTE *pixels)
  292.    {
  293.    if ( row < 0 || row >= sydots || start > sxdots || stop < 0 )
  294.       return ;
  295.  
  296.    if ( start < 0 )
  297.       {
  298.       pixels += -start;
  299.       start = 0;
  300.       }
  301.  
  302.    if ( stop >= sxdots )
  303.       stop = sxdots - 1;
  304.  
  305.    if ( start > stop )
  306.       return ;
  307.  
  308.    get_line(row, start, stop, pixels);
  309.    }
  310.  
  311.  
  312. void clip_putcolor(int x, int y, int color)
  313.    {
  314.    if ( x < 0 || y < 0 || x >= sxdots || y >= sydots )
  315.       return ;
  316.  
  317.    putcolor(x, y, color);
  318.    }
  319.  
  320.  
  321. int clip_getcolor(int x, int y)
  322.    {
  323.    if ( x < 0 || y < 0 || x >= sxdots || y >= sydots )
  324.       return (0);
  325.  
  326.    return ( getcolor(x, y) );
  327.    }
  328.  
  329.  
  330. void hline(int x, int y, int width, int color)
  331.    {
  332.    memset(line_buff, color, width);
  333.    clip_put_line(y, x, x+width-1, line_buff);
  334.    }
  335.  
  336.  
  337. void vline(int x, int y, int depth, int color)
  338.    {
  339.    while (depth-- > 0)
  340.       clip_putcolor(x, y++, color);
  341.    }
  342.  
  343.  
  344. void getrow(int x, int y, int width, char *buff)
  345.    {
  346.    clip_get_line(y, x, x+width-1, (BYTE *)buff);
  347.    }
  348.  
  349.  
  350. void putrow(int x, int y, int width, char *buff)
  351.    {
  352.    clip_put_line(y, x, x+width-1, (BYTE *)buff);
  353.    }
  354.  
  355.  
  356. static void vgetrow(int x, int y, int depth, char *buff)
  357.    {
  358.    while (depth-- > 0)
  359.       *buff++ = (char)clip_getcolor(x, y++);
  360.    }
  361.  
  362.  
  363. static void vputrow(int x, int y, int depth, char *buff)
  364.    {
  365.    while (depth-- > 0)
  366.       clip_putcolor(x, y++, (BYTE)(*buff++));
  367.    }
  368.  
  369.  
  370. static void fillrect(int x, int y, int width, int depth, int color)
  371.    {
  372.    while (depth-- > 0)
  373.       hline(x, y++, width, color);
  374.    }
  375.  
  376.  
  377. static void rect(int x, int y, int width, int depth, int color)
  378.    {
  379.    hline(x, y, width, color);
  380.    hline(x, y+depth-1, width, color);
  381.  
  382.    vline(x, y, depth, color);
  383.    vline(x+width-1, y, depth, color);
  384.    }
  385.  
  386.  
  387. void displayc(int x, int y, int fg, int bg, int ch)
  388.    {
  389.    int              xc, yc;
  390.    BYTE      t;
  391.    BYTE far *ptr;
  392.  
  393.    if( font8x8 == NULL)
  394.       if ( (font8x8 = findfont(0)) == NULL )
  395.          return ;
  396.  
  397.    ptr = ((BYTE far *)font8x8) + ch*FONT_DEPTH;
  398.  
  399.    for (yc=0; yc<FONT_DEPTH; yc++, y++, ++ptr)
  400.       {
  401.       for (xc=0, t= *ptr; xc<8; xc++, t<<=1)
  402.      line_buff[xc] = (BYTE)((t&0x80) ? fg : bg);
  403.       putrow(x, y, 8, (char *)line_buff);
  404.       }
  405.    }
  406.  
  407.  
  408. #ifndef XFRACT
  409. static void displayf(int x, int y, int fg, int bg, char *format, ...)
  410. #else
  411. static void displayf(va_alist)
  412. va_dcl
  413. #endif
  414.    {
  415.    char buff[81];
  416.    int  ctr;
  417.  
  418.    va_list arg_list;
  419.  
  420. #ifndef XFRACT
  421.    va_start(arg_list, format);
  422. #else
  423.    int x,y,fg,bg;
  424.    char *format;
  425.  
  426.    va_start(arg_list);
  427.    x = va_arg(arg_list,int);
  428.    y = va_arg(arg_list,int);
  429.    fg = va_arg(arg_list,int);
  430.    bg = va_arg(arg_list,int);
  431.    format = va_arg(arg_list,char *);
  432. #endif
  433.    vsprintf(buff, format, arg_list);
  434.    va_end(arg_list);
  435.  
  436.    for(ctr=0; buff[ctr]!='\0'; ctr++, x+=8)
  437.       displayc(x, y, fg, bg, buff[ctr]);
  438.    }
  439.  
  440.  
  441. /*
  442.  * create smooth shades between two colors
  443.  */
  444.  
  445.  
  446. static void mkpalrange(PALENTRY *p1, PALENTRY *p2, PALENTRY pal[], int num, int skip)
  447.    {
  448.    int      curr;
  449.    double rm = (double)((int) p2->red   - (int) p1->red  ) / num,
  450.       gm = (double)((int) p2->green - (int) p1->green) / num,
  451.       bm = (double)((int) p2->blue  - (int) p1->blue ) / num;
  452.  
  453.    for (curr=0; curr<num; curr+=skip)
  454.       {
  455.       if (gamma_val == 1)
  456.           {
  457.       pal[curr].red   = (BYTE)((p1->red   == p2->red  ) ? p1->red   :
  458.           (int) p1->red   + (int) ( rm * curr ));
  459.       pal[curr].green = (BYTE)((p1->green == p2->green) ? p1->green :
  460.           (int) p1->green + (int) ( gm * curr ));
  461.       pal[curr].blue  = (BYTE)((p1->blue  == p2->blue ) ? p1->blue  :
  462.           (int) p1->blue  + (int) ( bm * curr ));
  463.       }
  464.       else
  465.       {
  466.       pal[curr].red   = (BYTE)((p1->red   == p2->red  ) ? p1->red   :
  467.           (int) (p1->red   + pow(curr/(double)(num-1),gamma_val)*num*rm));
  468.       pal[curr].green = (BYTE)((p1->green == p2->green) ? p1->green :
  469.           (int) (p1->green + pow(curr/(double)(num-1),gamma_val)*num*gm));
  470.       pal[curr].blue  = (BYTE)((p1->blue  == p2->blue ) ? p1->blue  :
  471.           (int) (p1->blue  + pow(curr/(double)(num-1),gamma_val)*num*bm));
  472.       }
  473.       }
  474.    }
  475.  
  476.  
  477.  
  478. /*  Swap RG GB & RB columns */
  479.  
  480. static void rotcolrg(PALENTRY pal[], int num)
  481.    {
  482.    int      curr;
  483.    int    dummy;
  484.  
  485.     for (curr=0; curr<=num; curr++)
  486.       {
  487.       dummy = pal[curr].red;
  488.       pal[curr].red = pal[curr].green;
  489.       pal[curr].green = (BYTE)dummy;
  490.       }
  491.    }
  492.  
  493.  
  494. static void rotcolgb(PALENTRY pal[], int num)
  495.    {
  496.    int      curr;
  497.    int    dummy;
  498.  
  499.     for (curr=0; curr<=num; curr++)
  500.       {
  501.       dummy = pal[curr].green;
  502.       pal[curr].green = pal[curr].blue;
  503.       pal[curr].blue = (BYTE)dummy;
  504.       }
  505.    }
  506.  
  507. static void rotcolbr(PALENTRY pal[], int num)
  508.    {
  509.    int      curr;
  510.    int    dummy;
  511.  
  512.     for (curr=0; curr<=num; curr++)
  513.       {
  514.       dummy = pal[curr].red;
  515.       pal[curr].red = pal[curr].blue;
  516.       pal[curr].blue = (BYTE)dummy;
  517.       }
  518.    }
  519.  
  520.  
  521. /*
  522.  * convert a range of colors to grey scale
  523.  */
  524.  
  525.  
  526. static void palrangetogrey(PALENTRY pal[], int first, int how_many)
  527.    {
  528.    PALENTRY      *curr;
  529.    BYTE  val;
  530.  
  531.  
  532.    for (curr = &pal[first]; how_many>0; how_many--, curr++)
  533.       {
  534.       val = (BYTE) ( ((int)curr->red*30 + (int)curr->green*59 + (int)curr->blue*11) / 100 );
  535.       curr->red = curr->green = curr->blue = (BYTE)val;
  536.       }
  537.    }
  538.  
  539. /*
  540.  * convert a range of colors to their inverse
  541.  */
  542.  
  543.  
  544. static void palrangetonegative(PALENTRY pal[], int first, int how_many)
  545.    {
  546.    PALENTRY      *curr;
  547.  
  548.    for (curr = &pal[first]; how_many>0; how_many--, curr++)
  549.       {
  550.       curr->red   = (BYTE)(63 - curr->red);
  551.       curr->green = (BYTE)(63 - curr->green);
  552.       curr->blue  = (BYTE)(63 - curr->blue);
  553.       }
  554.    }
  555.  
  556.  
  557. /*
  558.  * draw and horizontal/vertical dotted lines
  559.  */
  560.  
  561.  
  562. static void hdline(int x, int y, int width)
  563.    {
  564.    int ctr;
  565.    BYTE *ptr;
  566.  
  567.    for (ctr=0, ptr=line_buff; ctr<width; ctr++, ptr++)
  568.       *ptr = (BYTE)((ctr&2) ? bg_color : fg_color);
  569.  
  570.    putrow(x, y, width, (char *)line_buff);
  571.    }
  572.  
  573.  
  574. static void vdline(int x, int y, int depth)
  575.    {
  576.    int ctr;
  577.  
  578.    for (ctr=0; ctr<depth; ctr++, y++)
  579.       clip_putcolor(x, y, (ctr&2) ? bg_color : fg_color);
  580.    }
  581.  
  582.  
  583. static void drect(int x, int y, int width, int depth)
  584.    {
  585.    hdline(x, y, width);
  586.    hdline(x, y+depth-1, width);
  587.  
  588.    vdline(x, y, depth);
  589.    vdline(x+width-1, y, depth);
  590.    }
  591.  
  592.  
  593. /*
  594.  * A very simple memory "allocator".
  595.  *
  596.  * Each call to mem_alloc() returns size bytes from the array mem_block.
  597.  *
  598.  * Be sure to call mem_init() before using mem_alloc()!
  599.  *
  600.  */
  601.  
  602. static char     *mem_block;
  603. static unsigned  mem_avail;
  604.  
  605.  
  606. void mem_init(VOIDPTR block, unsigned size)
  607.    {
  608.    mem_block = (char *)block;
  609.    mem_avail = size;
  610.    }
  611.  
  612.  
  613. VOIDPTR mem_alloc(unsigned size)
  614.    {
  615.    VOIDPTR block;
  616.  
  617. #ifndef XFRACT
  618.    if (size & 1)
  619.       ++size;   /* allocate even sizes */
  620. #else
  621.    size = (size+3)&~3; /* allocate word-aligned memory */
  622. #endif
  623.  
  624.    if (mem_avail < size)   /* don't let this happen! */
  625.       {
  626.       static FCODE msg[] = "editpal.c: Out of memory!\n";
  627.  
  628.       stopmsg(0, msg);
  629.       exit(1);
  630.       }
  631.  
  632.    block = mem_block;
  633.    mem_avail -= size;
  634.    mem_block += size;
  635.  
  636.    return(block);
  637.    }
  638.  
  639.  
  640.  
  641. /*
  642.  * misc. routines
  643.  *
  644.  */
  645.  
  646.  
  647. static BOOLEAN is_reserved(int color)
  648.    {
  649.    return ((BOOLEAN) ((reserve_colors && (color==(int)fg_color || color==(int)bg_color) ) ? TRUE : FALSE) );
  650.    }
  651.  
  652.  
  653.  
  654. static BOOLEAN is_in_box(int x, int y, int bx, int by, int bw, int bd)
  655.    {
  656.    return ((BOOLEAN) ((x >= bx) && (y >= by) && (x < bx+bw) && (y < by+bd)) );
  657.    }
  658.  
  659.  
  660.  
  661. static void draw_diamond(int x, int y, int color)
  662.    {
  663.    putcolor (x+2, y+0,      color);
  664.    hline    (x+1, y+1, 3, color);
  665.    hline    (x+0, y+2, 5, color);
  666.    hline    (x+1, y+3, 3, color);
  667.    putcolor (x+2, y+4,      color);
  668.    }
  669.  
  670.  
  671.  
  672. /*
  673.  * Class:     Cursor
  674.  *
  675.  * Purpose:   Draw the blinking cross-hair cursor.
  676.  *
  677.  * Note:      Only one Cursor can exist (referenced through the_cursor).
  678.  *          IMPORTANT: Call Cursor_Construct before you use any other
  679.  *          Cursor_ function!  Call Cursor_Destroy before exiting to
  680.  *          deallocate memory.
  681.  */
  682.  
  683. struct _Cursor
  684.    {
  685.  
  686.    int       x, y;
  687.    int       hidden;     /* >0 if mouse hidden */
  688.    long    last_blink;
  689.    BOOLEAN blink;
  690. #if 0
  691.    char    t[CURSOR_SIZE],      /* save line segments here */
  692.        b[CURSOR_SIZE],
  693.        l[CURSOR_SIZE],
  694.        r[CURSOR_SIZE];
  695. #endif
  696.    char    t[CURSOR_SIZE];      /* save line segments here */
  697.    char       b[CURSOR_SIZE];
  698.    char       l[CURSOR_SIZE];
  699.    char       r[CURSOR_SIZE];
  700.    } ;
  701.  
  702. #define Cursor struct _Cursor
  703.  
  704. /* private: */
  705.  
  706.    static  void    Cursor__Draw      (void);
  707.    static  void    Cursor__Save      (void);
  708.    static  void    Cursor__Restore   (void);
  709.  
  710. /* public: */
  711. #ifdef NOT_USED
  712.    static  BOOLEAN Cursor_IsHidden  (void);
  713. #endif
  714.  
  715.  
  716.  
  717. static Cursor *the_cursor = NULL;
  718.  
  719.  
  720. BOOLEAN Cursor_Construct(void)
  721.    {
  722.    if (the_cursor != NULL)
  723.       return(FALSE);
  724.  
  725.    the_cursor = new(Cursor);
  726.  
  727.    the_cursor->x      = sxdots/2;
  728.    the_cursor->y      = sydots/2;
  729.    the_cursor->hidden      = 1;
  730.    the_cursor->blink      = FALSE;
  731.    the_cursor->last_blink = 0;
  732.  
  733.    return (TRUE);
  734.    }
  735.  
  736.  
  737. void Cursor_Destroy(void)
  738.    {
  739.    if (the_cursor != NULL)
  740.       delete(the_cursor);
  741.  
  742.    the_cursor = NULL;
  743.    }
  744.  
  745.  
  746.  
  747. static void Cursor__Draw(void)
  748.    {
  749.    int color;
  750.  
  751.    find_special_colors();
  752.    color = (the_cursor->blink) ? color_medium : color_dark;
  753.  
  754.    vline(the_cursor->x, the_cursor->y-CURSOR_SIZE-1, CURSOR_SIZE, color);
  755.    vline(the_cursor->x, the_cursor->y+2,         CURSOR_SIZE, color);
  756.  
  757.    hline(the_cursor->x-CURSOR_SIZE-1, the_cursor->y, CURSOR_SIZE, color);
  758.    hline(the_cursor->x+2,          the_cursor->y, CURSOR_SIZE, color);
  759.    }
  760.  
  761.  
  762. static void Cursor__Save(void)
  763.    {
  764.    vgetrow(the_cursor->x, the_cursor->y-CURSOR_SIZE-1, CURSOR_SIZE, the_cursor->t);
  765.    vgetrow(the_cursor->x, the_cursor->y+2,           CURSOR_SIZE, the_cursor->b);
  766.  
  767.    getrow(the_cursor->x-CURSOR_SIZE-1, the_cursor->y,  CURSOR_SIZE, the_cursor->l);
  768.    getrow(the_cursor->x+2,           the_cursor->y,  CURSOR_SIZE, the_cursor->r);
  769.    }
  770.  
  771.  
  772. static void Cursor__Restore(void)
  773.    {
  774.    vputrow(the_cursor->x, the_cursor->y-CURSOR_SIZE-1, CURSOR_SIZE, the_cursor->t);
  775.    vputrow(the_cursor->x, the_cursor->y+2,           CURSOR_SIZE, the_cursor->b);
  776.  
  777.    putrow(the_cursor->x-CURSOR_SIZE-1, the_cursor->y,  CURSOR_SIZE, the_cursor->l);
  778.    putrow(the_cursor->x+2,           the_cursor->y,  CURSOR_SIZE, the_cursor->r);
  779.    }
  780.  
  781.  
  782.  
  783. void Cursor_SetPos(int x, int y)
  784.    {
  785.    if (!the_cursor->hidden)
  786.       Cursor__Restore();
  787.  
  788.    the_cursor->x = x;
  789.    the_cursor->y = y;
  790.  
  791.    if (!the_cursor->hidden)
  792.       {
  793.       Cursor__Save();
  794.       Cursor__Draw();
  795.       }
  796.    }
  797.  
  798. #ifdef NOT_USED
  799.  
  800. static int Cursor_IsHidden(void)
  801.    {
  802.    return ( the_cursor->hidden );
  803.    }
  804.  
  805.  
  806. #endif
  807.  
  808.  
  809. void Cursor_Move(int xoff, int yoff)
  810.    {
  811.    if ( !the_cursor->hidden )
  812.       Cursor__Restore();
  813.  
  814.    the_cursor->x += xoff;
  815.    the_cursor->y += yoff;
  816.  
  817.    if (the_cursor->x < 0)       the_cursor->x = 0;
  818.    if (the_cursor->y < 0)       the_cursor->y = 0;
  819.    if (the_cursor->x >= sxdots) the_cursor->x = sxdots-1;
  820.    if (the_cursor->y >= sydots) the_cursor->y = sydots-1;
  821.  
  822.    if ( !the_cursor->hidden )
  823.       {
  824.       Cursor__Save();
  825.       Cursor__Draw();
  826.       }
  827.    }
  828.  
  829.  
  830. int Cursor_GetX(void)   { return(the_cursor->x); }
  831.  
  832. int Cursor_GetY(void)   { return(the_cursor->y); }
  833.  
  834.  
  835. void Cursor_Hide(void)
  836.    {
  837.    if ( the_cursor->hidden++ == 0 )
  838.       Cursor__Restore();
  839.    }
  840.  
  841.  
  842. void Cursor_Show(void)
  843.    {
  844.    if ( --the_cursor->hidden == 0)
  845.       {
  846.       Cursor__Save();
  847.       Cursor__Draw();
  848.       }
  849.    }
  850.  
  851. #ifdef XFRACT
  852. void Cursor_StartMouseTracking()
  853. {
  854.     editpal_cursor = 1;
  855. }
  856.  
  857. void Cursor_EndMouseTracking()
  858. {
  859.     editpal_cursor = 0;
  860. }
  861. #endif
  862.  
  863. /* See if the cursor should blink yet, and blink it if so */
  864. void Cursor_CheckBlink(void)
  865. {
  866.    long tick;
  867.    tick = readticker();
  868.  
  869.    if ( (tick - the_cursor->last_blink) > CURSOR_BLINK_RATE )
  870.       {
  871.       the_cursor->blink = (BOOLEAN)((the_cursor->blink) ? FALSE : TRUE);
  872.       the_cursor->last_blink = tick;
  873.       if ( !the_cursor->hidden )
  874.      Cursor__Draw();
  875.       }
  876.    else if ( tick < the_cursor->last_blink )
  877.       the_cursor->last_blink = tick;
  878. }
  879.  
  880. int Cursor_WaitKey(void)   /* blink cursor while waiting for a key */
  881.    {
  882.  
  883. #ifndef XFRACT
  884.    while ( !keypressed() ) {
  885.        Cursor_CheckBlink();
  886.    }
  887. #else
  888.    while ( !waitkeypressed(1) ) {
  889.        Cursor_CheckBlink();
  890.    }
  891. #endif
  892.  
  893.    return( keypressed() );
  894.    }
  895.  
  896.  
  897.  
  898. /*
  899.  * Class:     MoveBox
  900.  *
  901.  * Purpose:   Handles the rectangular move/resize box.
  902.  */
  903.  
  904. struct _MoveBox
  905.    {
  906.    int        x, y;
  907.    int        base_width,
  908.         base_depth;
  909.    int        csize;
  910.    BOOLEAN  moved;
  911.    BOOLEAN  should_hide;
  912.    char    *t, *b,
  913.        *l, *r;
  914.    } ;
  915.  
  916. #define MoveBox struct _MoveBox
  917.  
  918. /* private: */
  919.  
  920.    static void       MoveBox__Draw     (MoveBox *this);
  921.    static void       MoveBox__Erase    (MoveBox *this);
  922.    static void       MoveBox__Move     (MoveBox *this, int key);
  923.  
  924. /* public: */
  925.  
  926.    static MoveBox *MoveBox_Construct  (int x, int y, int csize, int base_width,
  927.                       int base_depth);
  928.    static void       MoveBox_Destroy    (MoveBox *this);
  929.    static BOOLEAN  MoveBox_Process    (MoveBox *this); /* returns FALSE if ESCAPED */
  930.    static BOOLEAN  MoveBox_Moved      (MoveBox *this);
  931.    static BOOLEAN  MoveBox_ShouldHide (MoveBox *this);
  932.    static int       MoveBox_X          (MoveBox *this);
  933.    static int       MoveBox_Y          (MoveBox *this);
  934.    static int       MoveBox_CSize      (MoveBox *this);
  935.  
  936.    static void       MoveBox_SetPos     (MoveBox *this, int x, int y);
  937.    static void       MoveBox_SetCSize   (MoveBox *this, int csize);
  938.  
  939.  
  940.  
  941. static MoveBox *MoveBox_Construct(int x, int y, int csize, int base_width, int base_depth)
  942.    {
  943.    MoveBox *this = new(MoveBox);
  944.  
  945.    this->x         = x;
  946.    this->y         = y;
  947.    this->csize         = csize;
  948.    this->base_width  = base_width;
  949.    this->base_depth  = base_depth;
  950.    this->moved         = FALSE;
  951.    this->should_hide = FALSE;
  952.    this->t         = newx(sxdots);
  953.    this->b         = newx(sxdots);
  954.    this->l         = newx(sydots);
  955.    this->r         = newx(sydots);
  956.  
  957.    return(this);
  958.    }
  959.  
  960.  
  961. static void MoveBox_Destroy(MoveBox *this)
  962.    {
  963.    delete(this->t);
  964.    delete(this->b);
  965.    delete(this->l);
  966.    delete(this->r);
  967.    delete(this);
  968.    }
  969.  
  970.  
  971. static BOOLEAN MoveBox_Moved(MoveBox *this) { return(this->moved); }
  972.  
  973. static BOOLEAN MoveBox_ShouldHide(MoveBox *this) { return(this->should_hide); }
  974.  
  975. static int MoveBox_X(MoveBox *this)     { return(this->x); }
  976.  
  977. static int MoveBox_Y(MoveBox *this)     { return(this->y); }
  978.  
  979. static int MoveBox_CSize(MoveBox *this)  { return(this->csize); }
  980.  
  981.  
  982. static void MoveBox_SetPos(MoveBox *this, int x, int y)
  983.    {
  984.    this->x = x;
  985.    this->y = y;
  986.    }
  987.  
  988.  
  989. static void MoveBox_SetCSize(MoveBox *this, int csize)
  990.    {
  991.    this->csize = csize;
  992.    }
  993.  
  994.  
  995. static void MoveBox__Draw(MoveBox *this)  /* private */
  996.    {
  997.    int width = this->base_width + this->csize*16+1,
  998.        depth = this->base_depth + this->csize*16+1;
  999.    int x     = this->x,
  1000.        y     = this->y;
  1001.  
  1002.  
  1003.    getrow (x, y,     width, this->t);
  1004.    getrow (x, y+depth-1, width, this->b);
  1005.  
  1006.    vgetrow(x,          y, depth, this->l);
  1007.    vgetrow(x+width-1, y, depth, this->r);
  1008.  
  1009.    hdline(x, y,         width);
  1010.    hdline(x, y+depth-1, width);
  1011.  
  1012.    vdline(x,         y, depth);
  1013.    vdline(x+width-1, y, depth);
  1014.    }
  1015.  
  1016.  
  1017. static void MoveBox__Erase(MoveBox *this)   /* private */
  1018.    {
  1019.    int width = this->base_width + this->csize*16+1,
  1020.        depth = this->base_depth + this->csize*16+1;
  1021.  
  1022.    vputrow(this->x,        this->y, depth, this->l);
  1023.    vputrow(this->x+width-1, this->y, depth, this->r);
  1024.  
  1025.    putrow(this->x, this->y,        width, this->t);
  1026.    putrow(this->x, this->y+depth-1, width, this->b);
  1027.    }
  1028.  
  1029.  
  1030. #define BOX_INC     1
  1031. #define CSIZE_INC   2
  1032.  
  1033. static void MoveBox__Move(MoveBox *this, int key)
  1034.    {
  1035.    BOOLEAN done  = FALSE;
  1036.    BOOLEAN first = TRUE;
  1037.    int       xoff  = 0,
  1038.        yoff  = 0;
  1039.  
  1040.    while ( !done )
  1041.       {
  1042.       switch(key)
  1043.      {
  1044.      case RIGHT_ARROW_2:     xoff += BOX_INC*4;   break;
  1045.      case RIGHT_ARROW:     xoff += BOX_INC;     break;
  1046.      case LEFT_ARROW_2:     xoff -= BOX_INC*4;   break;
  1047.      case LEFT_ARROW:     xoff -= BOX_INC;     break;
  1048.      case DOWN_ARROW_2:     yoff += BOX_INC*4;   break;
  1049.      case DOWN_ARROW:     yoff += BOX_INC;     break;
  1050.      case UP_ARROW_2:     yoff -= BOX_INC*4;   break;
  1051.      case UP_ARROW:      yoff -= BOX_INC;     break;
  1052.  
  1053.      default:
  1054.         done = TRUE;
  1055.      }
  1056.  
  1057.       if (!done)
  1058.      {
  1059.      if (!first)
  1060.         getakey();         /* delete key from buffer */
  1061.      else
  1062.         first = FALSE;
  1063.      key = keypressed();   /* peek at the next one... */
  1064.      }
  1065.       }
  1066.  
  1067.    xoff += this->x;
  1068.    yoff += this->y;   /* (xoff,yoff) = new position */
  1069.  
  1070.    if (xoff < 0) xoff = 0;
  1071.    if (yoff < 0) yoff = 0;
  1072.  
  1073.    if (xoff+this->base_width+this->csize*16+1 > sxdots)
  1074.        xoff = sxdots - (this->base_width+this->csize*16+1);
  1075.  
  1076.    if (yoff+this->base_depth+this->csize*16+1 > sydots)
  1077.       yoff = sydots - (this->base_depth+this->csize*16+1);
  1078.  
  1079.    if ( xoff!=this->x || yoff!=this->y )
  1080.       {
  1081.       MoveBox__Erase(this);
  1082.       this->y = yoff;
  1083.       this->x = xoff;
  1084.       MoveBox__Draw(this);
  1085.       }
  1086.    }
  1087.  
  1088.  
  1089. static BOOLEAN MoveBox_Process(MoveBox *this)
  1090.    {
  1091.    int       key;
  1092.    int       orig_x     = this->x,
  1093.        orig_y     = this->y,
  1094.        orig_csize = this->csize;
  1095.  
  1096.    MoveBox__Draw(this);
  1097.  
  1098. #ifdef XFRACT
  1099.    Cursor_StartMouseTracking();
  1100. #endif
  1101.    for(;;)
  1102.       {
  1103.       Cursor_WaitKey();
  1104.       key = getakey();
  1105.  
  1106.       if (key==ENTER || key==ENTER_2 || key==ESC || key=='H' || key=='h')
  1107.      {
  1108.      if (this->x != orig_x || this->y != orig_y || this->csize != orig_csize)
  1109.         this->moved = TRUE;
  1110.      else
  1111.        this->moved = FALSE;
  1112.      break;
  1113.      }
  1114.  
  1115.       switch(key)
  1116.      {
  1117.      case UP_ARROW:
  1118.      case DOWN_ARROW:
  1119.      case LEFT_ARROW:
  1120.      case RIGHT_ARROW:
  1121.      case UP_ARROW_2:
  1122.      case DOWN_ARROW_2:
  1123.      case LEFT_ARROW_2:
  1124.      case RIGHT_ARROW_2:
  1125.         MoveBox__Move(this, key);
  1126.         break;
  1127.  
  1128.      case PAGE_UP:     /* shrink */
  1129.         if (this->csize > CSIZE_MIN)
  1130.            {
  1131.            int t = this->csize - CSIZE_INC;
  1132.            int change;
  1133.  
  1134.            if (t < CSIZE_MIN)
  1135.           t = CSIZE_MIN;
  1136.  
  1137.            MoveBox__Erase(this);
  1138.  
  1139.            change = this->csize - t;
  1140.            this->csize = t;
  1141.            this->x += (change*16) / 2;
  1142.            this->y += (change*16) / 2;
  1143.            MoveBox__Draw(this);
  1144.            }
  1145.         break;
  1146.  
  1147.      case PAGE_DOWN:   /* grow */
  1148.         {
  1149.         int max_width = min(sxdots, MAX_WIDTH);
  1150.  
  1151.         if (this->base_depth+(this->csize+CSIZE_INC)*16+1 < sydots  &&
  1152.             this->base_width+(this->csize+CSIZE_INC)*16+1 < max_width )
  1153.            {
  1154.            MoveBox__Erase(this);
  1155.            this->x -= (CSIZE_INC*16) / 2;
  1156.            this->y -= (CSIZE_INC*16) / 2;
  1157.            this->csize += CSIZE_INC;
  1158.            if (this->y+this->base_depth+this->csize*16+1 > sydots)
  1159.           this->y = sydots - (this->base_depth+this->csize*16+1);
  1160.            if (this->x+this->base_width+this->csize*16+1 > max_width)
  1161.           this->x = max_width - (this->base_width+this->csize*16+1);
  1162.            if (this->y < 0)
  1163.           this->y = 0;
  1164.            if (this->x < 0)
  1165.           this->x = 0;
  1166.            MoveBox__Draw(this);
  1167.            }
  1168.         }
  1169.         break;
  1170.      }
  1171.       }
  1172.  
  1173. #ifdef XFRACT
  1174.    Cursor_EndMouseTracking();
  1175. #endif
  1176.  
  1177.    MoveBox__Erase(this);
  1178.  
  1179.    this->should_hide = (BOOLEAN)((key == 'H' || key == 'h') ? TRUE : FALSE);
  1180.  
  1181.    return( (BOOLEAN)((key==ESC) ? FALSE : TRUE) );
  1182.    }
  1183.  
  1184.  
  1185.  
  1186. /*
  1187.  * Class:     CEditor
  1188.  *
  1189.  * Purpose:   Edits a single color component (R, G or B)
  1190.  *
  1191.  * Note:      Calls the "other_key" function to process keys it doesn't use.
  1192.  *          The "change" function is called whenever the value is changed
  1193.  *          by the CEditor.
  1194.  */
  1195.  
  1196. struct _CEditor
  1197.    {
  1198.    int         x, y;
  1199.    char      letter;
  1200.    int         val;
  1201.    BOOLEAN   done;
  1202.    BOOLEAN   hidden;
  1203. #ifndef XFRACT
  1204.    void    (*other_key)(int key, struct _CEditor *ce, VOIDPTR info);
  1205.    void    (*change)(struct _CEditor *ce, VOIDPTR info);
  1206. #else
  1207.    void    (*other_key)();
  1208.    void    (*change)();
  1209. #endif
  1210.    void     *info;
  1211.  
  1212.    } ;
  1213.  
  1214. #define CEditor struct _CEditor
  1215.  
  1216. /* public: */
  1217.  
  1218. #ifndef XFRACT
  1219.    static CEditor *CEditor_Construct( int x, int y, char letter,
  1220.                       void (*other_key)(int,CEditor*,void*),
  1221.                                       void (*change)(CEditor*,void*), VOIDPTR info);
  1222.    static void CEditor_Destroy     (CEditor *this);
  1223.    static void CEditor_Draw     (CEditor *this);
  1224.    static void CEditor_SetPos     (CEditor *this, int x, int y);
  1225.    static void CEditor_SetVal     (CEditor *this, int val);
  1226.    static int  CEditor_GetVal     (CEditor *this);
  1227.    static void CEditor_SetDone     (CEditor *this, BOOLEAN done);
  1228.    static void CEditor_SetHidden (CEditor *this, BOOLEAN hidden);
  1229.    static int  CEditor_Edit     (CEditor *this);
  1230. #else
  1231.    static CEditor *CEditor_Construct( int , int , char ,
  1232.                                     void (*other_key)(),
  1233.                                     void (*change)(), VOIDPTR );
  1234.    static void CEditor_Destroy         (CEditor *);
  1235.    static void CEditor_Draw    (CEditor *);
  1236.    static void CEditor_SetPos  (CEditor *, int , int );
  1237.    static void CEditor_SetVal  (CEditor *, int );
  1238.    static int  CEditor_GetVal  (CEditor *);
  1239.    static void CEditor_SetDone         (CEditor *, BOOLEAN );
  1240.    static void CEditor_SetHidden (CEditor *, BOOLEAN );
  1241.    static int  CEditor_Edit    (CEditor *);
  1242. #endif
  1243.  
  1244. #define CEditor_WIDTH (8*3+4)
  1245. #define CEditor_DEPTH (8+4)
  1246.  
  1247.  
  1248.  
  1249. #ifndef XFRACT
  1250. static CEditor *CEditor_Construct( int x, int y, char letter,
  1251.                    void (*other_key)(int,CEditor*,VOIDPTR),
  1252.                    void (*change)(CEditor*, VOIDPTR), VOIDPTR info)
  1253. #else
  1254. static CEditor *CEditor_Construct( int x, int y, char letter,
  1255.                                    void (*other_key)(),
  1256.                                    void (*change)(), VOIDPTR info)
  1257. #endif
  1258.    {
  1259.    CEditor *this = new(CEditor);
  1260.  
  1261.    this->x       = x;
  1262.    this->y       = y;
  1263.    this->letter    = letter;
  1264.    this->val       = 0;
  1265.    this->other_key = other_key;
  1266.    this->hidden    = FALSE;
  1267.    this->change    = change;
  1268.    this->info       = info;
  1269.  
  1270.    return(this);
  1271.    }
  1272.  
  1273. #ifdef __TURBOC__
  1274. #   pragma argsused   /* kills "arg not used" warning */
  1275. #endif
  1276. #ifdef __CLINT__
  1277. #   pragma argsused   /* kills "arg not used" warning */
  1278. #endif
  1279.  
  1280. static void CEditor_Destroy(CEditor *this)
  1281.    {
  1282.    delete(this);
  1283.    }
  1284.  
  1285.  
  1286. static void CEditor_Draw(CEditor *this)
  1287.    {
  1288.    if (this->hidden)
  1289.       return;
  1290.  
  1291.    Cursor_Hide();
  1292.    displayf(this->x+2, this->y+2, fg_color, bg_color, "%c%02d", this->letter, this->val);
  1293.    Cursor_Show();
  1294.    }
  1295.  
  1296.  
  1297. static void CEditor_SetPos(CEditor *this, int x, int y)
  1298.    {
  1299.    this->x = x;
  1300.    this->y = y;
  1301.    }
  1302.  
  1303.  
  1304. static void CEditor_SetVal(CEditor *this, int val)
  1305.    {
  1306.    this->val = val;
  1307.    }
  1308.  
  1309.  
  1310. static int CEditor_GetVal(CEditor *this)
  1311.    {
  1312.    return(this->val);
  1313.    }
  1314.  
  1315.  
  1316. static void CEditor_SetDone(CEditor *this, BOOLEAN done)
  1317.    {
  1318.    this->done = done;
  1319.    }
  1320.  
  1321.  
  1322. static void CEditor_SetHidden(CEditor *this, BOOLEAN hidden)
  1323.    {
  1324.    this->hidden = hidden;
  1325.    }
  1326.  
  1327.  
  1328. static int CEditor_Edit(CEditor *this)
  1329.    {
  1330.    int key;
  1331.    int diff;
  1332.  
  1333.    this->done = FALSE;
  1334.  
  1335.    if (!this->hidden)
  1336.       {
  1337.       Cursor_Hide();
  1338.       rect(this->x, this->y, CEditor_WIDTH, CEditor_DEPTH, fg_color);
  1339.       Cursor_Show();
  1340.       }
  1341.  
  1342. #ifdef XFRACT
  1343.    Cursor_StartMouseTracking();
  1344. #endif
  1345.    while ( !this->done )
  1346.       {
  1347.       Cursor_WaitKey();
  1348.       key = getakey();
  1349.  
  1350.       switch( key )
  1351.      {
  1352.      case PAGE_UP:
  1353.         if (this->val < 63)
  1354.            {
  1355.            this->val += 5;
  1356.            if (this->val > 63)
  1357.           this->val = 63;
  1358.            CEditor_Draw(this);
  1359.            this->change(this, this->info);
  1360.            }
  1361.         break;
  1362.  
  1363.      case '+':
  1364.      case CTL_PLUS:        /*RB*/
  1365.         diff = 1;
  1366.         while ( keypressed() == key )
  1367.            {
  1368.            getakey();
  1369.            ++diff;
  1370.            }
  1371.         if (this->val < 63)
  1372.            {
  1373.            this->val += diff;
  1374.            if (this->val > 63)
  1375.           this->val = 63;
  1376.            CEditor_Draw(this);
  1377.            this->change(this, this->info);
  1378.            }
  1379.         break;
  1380.  
  1381.      case PAGE_DOWN:
  1382.         if (this->val > 0)
  1383.            {
  1384.            this->val -= 5;
  1385.            if (this->val < 0)
  1386.           this->val = 0;
  1387.            CEditor_Draw(this);
  1388.            this->change(this, this->info);
  1389.            } break;
  1390.  
  1391.      case '-':
  1392.      case CTL_MINUS:     /*RB*/
  1393.         diff = 1;
  1394.         while ( keypressed() == key )
  1395.            {
  1396.            getakey();
  1397.            ++diff;
  1398.            }
  1399.         if (this->val > 0)
  1400.            {
  1401.            this->val -= diff;
  1402.            if (this->val < 0)
  1403.           this->val = 0;
  1404.            CEditor_Draw(this);
  1405.            this->change(this, this->info);
  1406.            }
  1407.         break;
  1408.  
  1409.      case '0':
  1410.      case '1':
  1411.      case '2':
  1412.      case '3':
  1413.      case '4':
  1414.      case '5':
  1415.      case '6':
  1416.      case '7':
  1417.      case '8':
  1418.      case '9':
  1419.         this->val = (key - '0') * 10;
  1420.         if (this->val > 63)
  1421.            this->val = 63;
  1422.         CEditor_Draw(this);
  1423.         this->change(this, this->info);
  1424.         break;
  1425.  
  1426.      default:
  1427.         this->other_key(key, this, this->info);
  1428.         break;
  1429.      } /* switch */
  1430.       } /* while */
  1431. #ifdef XFRACT
  1432.    Cursor_EndMouseTracking();
  1433. #endif
  1434.  
  1435.    if (!this->hidden)
  1436.       {
  1437.       Cursor_Hide();
  1438.       rect(this->x, this->y, CEditor_WIDTH, CEditor_DEPTH, bg_color);
  1439.       Cursor_Show();
  1440.       }
  1441.  
  1442.    return(key);
  1443.    }
  1444.  
  1445.  
  1446.  
  1447. /*
  1448.  * Class:     RGBEditor
  1449.  *
  1450.  * Purpose:   Edits a complete color using three CEditors for R, G and B
  1451.  */
  1452.  
  1453. struct _RGBEditor
  1454.    {
  1455.    int         x, y;          /* position */
  1456.    int         curr;          /* 0=r, 1=g, 2=b */
  1457.    int         pal;          /* palette number */
  1458.    BOOLEAN   done;
  1459.    BOOLEAN   hidden;
  1460.    CEditor  *color[3];          /* color editors 0=r, 1=g, 2=b */
  1461. #ifndef XFRACT
  1462.    void    (*other_key)(int key, struct _RGBEditor *e, VOIDPTR info);
  1463.    void    (*change)(struct _RGBEditor *e, VOIDPTR info);
  1464. #else
  1465.    void    (*other_key)();
  1466.    void    (*change)();
  1467. #endif
  1468.    void     *info;
  1469.    } ;
  1470.  
  1471. #define RGBEditor struct _RGBEditor
  1472.  
  1473. /* private: */
  1474.  
  1475.    static void      RGBEditor__other_key (int key, CEditor *ceditor, VOIDPTR info);
  1476.    static void      RGBEditor__change    (CEditor *ceditor, VOIDPTR info);
  1477.  
  1478. /* public: */
  1479.  
  1480. #ifndef XFRACT
  1481.    static RGBEditor *RGBEditor_Construct(int x, int y,
  1482.              void (*other_key)(int,RGBEditor*,void*),
  1483.              void (*change)(RGBEditor*,void*), VOIDPTR info);
  1484. #else
  1485.    static RGBEditor *RGBEditor_Construct(int x, int y,
  1486.                      void (*other_key)(),
  1487.                      void (*change)(), VOIDPTR info);
  1488. #endif
  1489.  
  1490.    static void       RGBEditor_Destroy  (RGBEditor *this);
  1491.    static void       RGBEditor_SetPos   (RGBEditor *this, int x, int y);
  1492.    static void       RGBEditor_SetDone  (RGBEditor *this, BOOLEAN done);
  1493.    static void       RGBEditor_SetHidden(RGBEditor *this, BOOLEAN hidden);
  1494.    static void       RGBEditor_BlankSampleBox(RGBEditor *this);
  1495.    static void       RGBEditor_Update   (RGBEditor *this);
  1496.    static void       RGBEditor_Draw     (RGBEditor *this);
  1497.    static int       RGBEditor_Edit     (RGBEditor *this);
  1498.    static void       RGBEditor_SetRGB   (RGBEditor *this, int pal, PALENTRY *rgb);
  1499.    static PALENTRY RGBEditor_GetRGB   (RGBEditor *this);
  1500.  
  1501. #define RGBEditor_WIDTH 62
  1502. #define RGBEditor_DEPTH (1+1+CEditor_DEPTH*3-2+2)
  1503.  
  1504. #define RGBEditor_BWIDTH ( RGBEditor_WIDTH - (2+CEditor_WIDTH+1 + 2) )
  1505. #define RGBEditor_BDEPTH ( RGBEditor_DEPTH - 4 )
  1506.  
  1507.  
  1508.  
  1509. #ifndef XFRACT
  1510. static RGBEditor *RGBEditor_Construct(int x, int y, void (*other_key)(int,RGBEditor*,void*),
  1511.                       void (*change)(RGBEditor*,void*), VOIDPTR info)
  1512. #else
  1513. static RGBEditor *RGBEditor_Construct(int x, int y, void (*other_key)(),
  1514.                                       void (*change)(), VOIDPTR info)
  1515. #endif
  1516.    {
  1517.    RGBEditor      *this     = new(RGBEditor);
  1518.    static FCODE letter[] = "RGB";
  1519.    int           ctr;
  1520.  
  1521.    for (ctr=0; ctr<3; ctr++)
  1522.       this->color[ctr] = CEditor_Construct(0, 0, letter[ctr], RGBEditor__other_key,
  1523.                        RGBEditor__change, this);
  1524.  
  1525.    RGBEditor_SetPos(this, x, y);
  1526.    this->curr       = 0;
  1527.    this->pal       = 1;
  1528.    this->hidden    = FALSE;
  1529.    this->other_key = other_key;
  1530.    this->change    = change;
  1531.    this->info       = info;
  1532.  
  1533.    return(this);
  1534.    }
  1535.  
  1536.  
  1537. static void RGBEditor_Destroy(RGBEditor *this)
  1538.    {
  1539.    CEditor_Destroy(this->color[0]);
  1540.    CEditor_Destroy(this->color[1]);
  1541.    CEditor_Destroy(this->color[2]);
  1542.    delete(this);
  1543.    }
  1544.  
  1545.  
  1546. static void RGBEditor_SetDone(RGBEditor *this, BOOLEAN done)
  1547.    {
  1548.    this->done = done;
  1549.    }
  1550.  
  1551.  
  1552. static void RGBEditor_SetHidden(RGBEditor *this, BOOLEAN hidden)
  1553.    {
  1554.    this->hidden = hidden;
  1555.    CEditor_SetHidden(this->color[0], hidden);
  1556.    CEditor_SetHidden(this->color[1], hidden);
  1557.    CEditor_SetHidden(this->color[2], hidden);
  1558.    }
  1559.  
  1560.  
  1561. static void RGBEditor__other_key(int key, CEditor *ceditor, VOIDPTR info) /* private */
  1562.    {
  1563.    RGBEditor *this = (RGBEditor *)info;
  1564.  
  1565.    switch( key )
  1566.       {
  1567.       case 'R':
  1568.       case 'r':
  1569.      if (this->curr != 0)
  1570.         {
  1571.         this->curr = 0;
  1572.         CEditor_SetDone(ceditor, TRUE);
  1573.         }
  1574.      break;
  1575.  
  1576.       case 'G':
  1577.       case 'g':
  1578.      if (this->curr != 1)
  1579.         {
  1580.         this->curr = 1;
  1581.         CEditor_SetDone(ceditor, TRUE);
  1582.         }
  1583.      break;
  1584.  
  1585.       case 'B':
  1586.       case 'b':
  1587.      if (this->curr != 2)
  1588.         {
  1589.         this->curr = 2;
  1590.         CEditor_SetDone(ceditor, TRUE);
  1591.         }
  1592.      break;
  1593.  
  1594.       case DELETE:   /* move to next CEditor */
  1595.       case CTL_ENTER_2:    /*double click rt mouse also! */
  1596.      if ( ++this->curr > 2)
  1597.         this->curr = 0;
  1598.      CEditor_SetDone(ceditor, TRUE);
  1599.      break;
  1600.  
  1601.       case INSERT:   /* move to prev CEditor */
  1602.      if ( --this->curr < 0)
  1603.         this->curr = 2;
  1604.      CEditor_SetDone(ceditor, TRUE);
  1605.      break;
  1606.  
  1607.       default:
  1608.      this->other_key(key, this, this->info);
  1609.      if (this->done)
  1610.         CEditor_SetDone(ceditor, TRUE);
  1611.      break;
  1612.       }
  1613.    }
  1614.  
  1615. #ifdef __TURBOC__
  1616. #   pragma argsused   /* kills "arg not used" warning */
  1617. #endif
  1618. #ifdef __CLINT__
  1619. #   pragma argsused   /* kills "arg not used" warning */
  1620. #endif
  1621.  
  1622. static void RGBEditor__change(CEditor *ceditor, VOIDPTR info) /* private */
  1623.    {
  1624.    RGBEditor *this = (RGBEditor *)info;
  1625.  
  1626.    ceditor = NULL; /* just for warning */
  1627.    if ( this->pal < colors && !is_reserved(this->pal) )
  1628.       setpal(this->pal, CEditor_GetVal(this->color[0]),
  1629.       CEditor_GetVal(this->color[1]), CEditor_GetVal(this->color[2]));
  1630.  
  1631.    this->change(this, this->info);
  1632.    }
  1633.  
  1634.  
  1635. static void RGBEditor_SetPos(RGBEditor *this, int x, int y)
  1636.    {
  1637.    this->x = x;
  1638.    this->y = y;
  1639.  
  1640.    CEditor_SetPos(this->color[0], x+2, y+2);
  1641.    CEditor_SetPos(this->color[1], x+2, y+2+CEditor_DEPTH-1);
  1642.    CEditor_SetPos(this->color[2], x+2, y+2+CEditor_DEPTH-1+CEditor_DEPTH-1);
  1643.    }
  1644.  
  1645.  
  1646. static void RGBEditor_BlankSampleBox(RGBEditor *this)
  1647.    {
  1648.    if (this->hidden)
  1649.       return ;
  1650.  
  1651.    Cursor_Hide();
  1652.    fillrect(this->x+2+CEditor_WIDTH+1+1, this->y+2+1, RGBEditor_BWIDTH-2, RGBEditor_BDEPTH-2, bg_color);
  1653.    Cursor_Show();
  1654.    }
  1655.  
  1656.  
  1657. static void RGBEditor_Update(RGBEditor *this)
  1658.    {
  1659.    int x1 = this->x+2+CEditor_WIDTH+1+1,
  1660.        y1 = this->y+2+1;
  1661.  
  1662.    if (this->hidden)
  1663.       return ;
  1664.  
  1665.    Cursor_Hide();
  1666.  
  1667.    if ( this->pal >= colors )
  1668.       {
  1669.       fillrect(x1, y1, RGBEditor_BWIDTH-2, RGBEditor_BDEPTH-2, bg_color);
  1670.       draw_diamond(x1+(RGBEditor_BWIDTH-5)/2, y1+(RGBEditor_BDEPTH-5)/2, fg_color);
  1671.       }
  1672.  
  1673.    else if ( is_reserved(this->pal) )
  1674.       {
  1675.       int x2 = x1+RGBEditor_BWIDTH-3,
  1676.       y2 = y1+RGBEditor_BDEPTH-3;
  1677.  
  1678.       fillrect(x1, y1, RGBEditor_BWIDTH-2, RGBEditor_BDEPTH-2, bg_color);
  1679.       draw_line(x1, y1, x2, y2, fg_color);
  1680.       draw_line(x1, y2, x2, y1, fg_color);
  1681.       }
  1682.    else
  1683.       fillrect(x1, y1, RGBEditor_BWIDTH-2, RGBEditor_BDEPTH-2, this->pal);
  1684.  
  1685.    CEditor_Draw(this->color[0]);
  1686.    CEditor_Draw(this->color[1]);
  1687.    CEditor_Draw(this->color[2]);
  1688.    Cursor_Show();
  1689.    }
  1690.  
  1691.  
  1692. static void RGBEditor_Draw(RGBEditor *this)
  1693.    {
  1694.    if (this->hidden)
  1695.       return ;
  1696.  
  1697.    Cursor_Hide();
  1698.    drect(this->x, this->y, RGBEditor_WIDTH, RGBEditor_DEPTH);
  1699.    fillrect(this->x+1, this->y+1, RGBEditor_WIDTH-2, RGBEditor_DEPTH-2, bg_color);
  1700.    rect(this->x+1+CEditor_WIDTH+2, this->y+2, RGBEditor_BWIDTH, RGBEditor_BDEPTH, fg_color);
  1701.    RGBEditor_Update(this);
  1702.    Cursor_Show();
  1703.    }
  1704.  
  1705.  
  1706. static int RGBEditor_Edit(RGBEditor *this)
  1707.    {
  1708.    int key;
  1709.  
  1710.    this->done = FALSE;
  1711.  
  1712.    if (!this->hidden)
  1713.       {
  1714.       Cursor_Hide();
  1715.       rect(this->x, this->y, RGBEditor_WIDTH, RGBEditor_DEPTH, fg_color);
  1716.       Cursor_Show();
  1717.       }
  1718.  
  1719.    while ( !this->done )
  1720.       key = CEditor_Edit( this->color[this->curr] );
  1721.  
  1722.    if (!this->hidden)
  1723.       {
  1724.       Cursor_Hide();
  1725.       drect(this->x, this->y, RGBEditor_WIDTH, RGBEditor_DEPTH);
  1726.       Cursor_Show();
  1727.       }
  1728.  
  1729.    return (key);
  1730.    }
  1731.  
  1732.  
  1733. static void RGBEditor_SetRGB(RGBEditor *this, int pal, PALENTRY *rgb)
  1734.    {
  1735.    this->pal = pal;
  1736.    CEditor_SetVal(this->color[0], rgb->red);
  1737.    CEditor_SetVal(this->color[1], rgb->green);
  1738.    CEditor_SetVal(this->color[2], rgb->blue);
  1739.    }
  1740.  
  1741.  
  1742. static PALENTRY RGBEditor_GetRGB(RGBEditor *this)
  1743.    {
  1744.    PALENTRY pal;
  1745.  
  1746.    pal.red   = (BYTE)CEditor_GetVal(this->color[0]);
  1747.    pal.green = (BYTE)CEditor_GetVal(this->color[1]);
  1748.    pal.blue  = (BYTE)CEditor_GetVal(this->color[2]);
  1749.  
  1750.    return(pal);
  1751.    }
  1752.  
  1753.  
  1754.  
  1755. /*
  1756.  * Class:     PalTable
  1757.  *
  1758.  * Purpose:   This is where it all comes together.  Creates the two RGBEditors
  1759.  *          and the palette. Moves the cursor, hides/restores the screen,
  1760.  *          handles (S)hading, (C)opying, e(X)clude mode, the "Y" exclusion
  1761.  *          mode, (Z)oom option, (H)ide palette, rotation, etc.
  1762.  *
  1763.  */
  1764.  
  1765. enum stored_at_values
  1766.    {
  1767.    NOWHERE,
  1768.    DISK,
  1769.    MEMORY
  1770.    } ;
  1771.  
  1772. /*
  1773.  
  1774. Modes:
  1775.    Auto:          "A", " "
  1776.    Exclusion:     "X", "Y", " "
  1777.    Freestyle:     "F", " "
  1778.    S(t)ripe mode: "T", " "
  1779.  
  1780. */
  1781.  
  1782.  
  1783.  
  1784. struct  _PalTable
  1785.    {
  1786.    int         x, y;
  1787.    int         csize;
  1788.    int         active;   /* which RGBEditor is active (0,1) */
  1789.    int         curr[2];
  1790.    RGBEditor    *rgb[2];
  1791.    MoveBox      *movebox;
  1792.    BOOLEAN     done;
  1793.    BOOLEAN     exclude;
  1794.    BOOLEAN     auto_select;
  1795.    PALENTRY     pal[256];
  1796.    FILE         *undo_file;
  1797.    BOOLEAN       curr_changed;
  1798.    int           num_redo;
  1799.    int         hidden;
  1800.    int         stored_at;
  1801.    FILE         *file;
  1802.    char far     *memory;
  1803.  
  1804.    PALENTRY far *save_pal[8];
  1805.  
  1806.    PALENTRY      fs_color;
  1807.    int           top,bottom; /* top and bottom colours of freestyle band */
  1808.    int           bandwidth; /*size of freestyle colour band */
  1809.    BOOLEAN       freestyle;
  1810.    } ;
  1811.  
  1812. #define PalTable struct _PalTable
  1813.  
  1814. /* private: */
  1815.  
  1816.    static void    PalTable__DrawStatus  (PalTable *this, BOOLEAN stripe_mode);
  1817.    static void      PalTable__HlPal       (PalTable *this, int pnum, int color);
  1818.    static void      PalTable__Draw        (PalTable *this);
  1819.    static BOOLEAN PalTable__SetCurr     (PalTable *this, int which, int curr);
  1820.    static BOOLEAN PalTable__MemoryAlloc (PalTable *this, long size);
  1821.    static void      PalTable__SaveRect    (PalTable *this);
  1822.    static void      PalTable__RestoreRect (PalTable *this);
  1823.    static void      PalTable__SetPos      (PalTable *this, int x, int y);
  1824.    static void      PalTable__SetCSize    (PalTable *this, int csize);
  1825.    static int      PalTable__GetCursorColor(PalTable *this);
  1826.    static void      PalTable__DoCurs      (PalTable *this, int key);
  1827.    static void      PalTable__Rotate      (PalTable *this, int dir, int lo, int hi);
  1828.    static void      PalTable__UpdateDAC   (PalTable *this);
  1829.    static void    PalTable__other_key   (int key, RGBEditor *rgb, VOIDPTR info);
  1830.    static void    PalTable__SaveUndoData(PalTable *this, int first, int last);
  1831.    static void    PalTable__SaveUndoRotate(PalTable *this, int dir, int first, int last);
  1832.    static void    PalTable__UndoProcess (PalTable *this, int delta);
  1833.    static void    PalTable__Undo        (PalTable *this);
  1834.    static void    PalTable__Redo        (PalTable *this);
  1835.    static void    PalTable__change      (RGBEditor *rgb, VOIDPTR info);
  1836.  
  1837. /* public: */
  1838.  
  1839.    static PalTable *PalTable_Construct (void);
  1840.    static void        PalTable_Destroy   (PalTable *this);
  1841.    static void        PalTable_Process   (PalTable *this);
  1842.    static void        PalTable_SetHidden (PalTable *this, BOOLEAN hidden);
  1843.    static void        PalTable_Hide      (PalTable *this, RGBEditor *rgb, BOOLEAN hidden);
  1844.  
  1845.  
  1846. #define PalTable_PALX (1)
  1847. #define PalTable_PALY (2+RGBEditor_DEPTH+2)
  1848.  
  1849. #define UNDO_DATA        (1)
  1850. #define UNDO_DATA_SINGLE (2)
  1851. #define UNDO_ROTATE      (3)
  1852.  
  1853. /*  - Freestyle code - */
  1854.  
  1855. static void PalTable__CalcTopBottom(PalTable *this)
  1856.    {
  1857.    if (this->curr[this->active] < this->bandwidth )
  1858.       this->bottom = 0;
  1859.    else
  1860.       this->bottom = (this->curr[this->active]) - this->bandwidth;
  1861.  
  1862.    if (this->curr[this->active] > (255-this->bandwidth) )
  1863.       this->top = 255;
  1864.    else
  1865.       this->top = (this->curr[this->active]) + this->bandwidth;
  1866.    }
  1867.  
  1868. static void PalTable__PutBand(PalTable *this, PALENTRY *pal)
  1869.    {
  1870.    int r,b,a;
  1871.  
  1872.   /* clip top and bottom values to stop them running off the end of the DAC */
  1873.  
  1874.    PalTable__CalcTopBottom(this);
  1875.  
  1876.   /* put bands either side of current colour */
  1877.  
  1878.    a = this->curr[this->active];
  1879.    b = this->bottom;
  1880.    r = this->top;
  1881.  
  1882.    pal[a] = this->fs_color;
  1883.  
  1884.    if (r != a && a != b)
  1885.       {
  1886.       mkpalrange(&pal[a], &pal[r], &pal[a], r-a, 1);
  1887.       mkpalrange(&pal[b], &pal[a], &pal[b], a-b, 1);
  1888.       }
  1889.  
  1890.    }
  1891.  
  1892.  
  1893. /* - Undo.Redo code - */
  1894.  
  1895.  
  1896. static void PalTable__SaveUndoData(PalTable *this, int first, int last)
  1897.    {
  1898.    int num;
  1899.  
  1900.    if ( this->undo_file == NULL )
  1901.       return ;
  1902.  
  1903.    num = (last - first) + 1;
  1904.  
  1905. #ifdef DEBUG_UNDO
  1906.    mprintf("%6ld Writing Undo DATA from %d to %d (%d)", ftell(this->undo_file), first, last, num);
  1907. #endif
  1908.  
  1909.    fseek(this->undo_file, 0, SEEK_CUR);
  1910.    if ( num == 1 )
  1911.       {
  1912.       putc(UNDO_DATA_SINGLE, this->undo_file);
  1913.       putc(first, this->undo_file);
  1914.       fwrite(this->pal+first, 3, 1, this->undo_file);
  1915.       putw( 1 + 1 + 3 + sizeof(int), this->undo_file);
  1916.       }
  1917.    else
  1918.       {
  1919.       putc(UNDO_DATA, this->undo_file);
  1920.       putc(first, this->undo_file);
  1921.       putc(last,  this->undo_file);
  1922.       fwrite(this->pal+first, 3, num, this->undo_file);
  1923.       putw(1 + 2 + (num*3) + sizeof(int), this->undo_file);
  1924.       }
  1925.  
  1926.    this->num_redo = 0;
  1927.    }
  1928.  
  1929.  
  1930. static void PalTable__SaveUndoRotate(PalTable *this, int dir, int first, int last)
  1931.    {
  1932.    if ( this->undo_file == NULL )
  1933.       return ;
  1934.  
  1935. #ifdef DEBUG_UNDO
  1936.    mprintf("%6ld Writing Undo ROTATE of %d from %d to %d", ftell(this->undo_file), dir, first, last);
  1937. #endif
  1938.  
  1939.    fseek(this->undo_file, 0, SEEK_CUR);
  1940.    putc(UNDO_ROTATE, this->undo_file);
  1941.    putc(first, this->undo_file);
  1942.    putc(last,  this->undo_file);
  1943.    putw(dir, this->undo_file);
  1944.    putw(1 + 2 + sizeof(int), this->undo_file);
  1945.  
  1946.    this->num_redo = 0;
  1947.    }
  1948.  
  1949.  
  1950. static void PalTable__UndoProcess(PalTable *this, int delta)   /* undo/redo common code */
  1951.    {              /* delta = -1 for undo, +1 for redo */
  1952.    int cmd = getc(this->undo_file);
  1953.  
  1954.    switch( cmd )
  1955.       {
  1956.       case UNDO_DATA:
  1957.       case UNDO_DATA_SINGLE:
  1958.          {
  1959.          int      first, last, num;
  1960.          PALENTRY temp[256];
  1961.  
  1962.          if ( cmd == UNDO_DATA )
  1963.             {
  1964.             first = (unsigned char)getc(this->undo_file);
  1965.             last  = (unsigned char)getc(this->undo_file);
  1966.             }
  1967.          else  /* UNDO_DATA_SINGLE */
  1968.             first = last = (unsigned char)getc(this->undo_file);
  1969.  
  1970.          num = (last - first) + 1;
  1971.  
  1972. #ifdef DEBUG_UNDO
  1973.          mprintf("          Reading DATA from %d to %d", first, last);
  1974. #endif
  1975.  
  1976.          fread(temp, 3, num, this->undo_file);
  1977.  
  1978.          fseek(this->undo_file, -(num*3), SEEK_CUR);  /* go to start of undo/redo data */
  1979.          fwrite(this->pal+first, 3, num, this->undo_file);  /* write redo/undo data */
  1980.  
  1981.          memmove(this->pal+first, temp, num*3);
  1982.  
  1983.          PalTable__UpdateDAC(this);
  1984.  
  1985.          RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]]));
  1986.          RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]]));
  1987.          RGBEditor_Update(this->rgb[0]);
  1988.          RGBEditor_Update(this->rgb[1]);
  1989.          break;
  1990.          }
  1991.  
  1992.       case UNDO_ROTATE:
  1993.          {
  1994.          int first = (unsigned char)getc(this->undo_file);
  1995.          int last  = (unsigned char)getc(this->undo_file);
  1996.          int dir   = getw(this->undo_file);
  1997.  
  1998. #ifdef DEBUG_UNDO
  1999.          mprintf("          Reading ROTATE of %d from %d to %d", dir, first, last);
  2000. #endif
  2001.          PalTable__Rotate(this, delta*dir, first, last);
  2002.          break;
  2003.          }
  2004.  
  2005.       default:
  2006. #ifdef DEBUG_UNDO
  2007.          mprintf("          Unknown command: %d", cmd);
  2008. #endif
  2009.          break;
  2010.       }
  2011.  
  2012.    fseek(this->undo_file, 0, SEEK_CUR);  /* to put us in read mode */
  2013.    getw(this->undo_file);  /* read size */
  2014.    }
  2015.  
  2016.  
  2017. static void PalTable__Undo(PalTable *this)
  2018.    {
  2019.    int  size;
  2020.    long pos;
  2021.  
  2022.    if ( ftell(this->undo_file) <= 0  )   /* at beginning of file? */
  2023.       {                                  /*   nothing to undo -- exit */
  2024.       return ;
  2025.       }
  2026.  
  2027.    fseek(this->undo_file, -(int)sizeof(int), SEEK_CUR);  /* go back to get size */
  2028.  
  2029.    size = getw(this->undo_file);
  2030.    fseek(this->undo_file, -size, SEEK_CUR);   /* go to start of undo */
  2031.  
  2032. #ifdef DEBUG_UNDO
  2033.    mprintf("%6ld Undo:", ftell(this->undo_file));
  2034. #endif
  2035.  
  2036.    pos = ftell(this->undo_file);
  2037.  
  2038.    PalTable__UndoProcess(this, -1);
  2039.  
  2040.    fseek(this->undo_file, pos, SEEK_SET);   /* go to start of this block */
  2041.  
  2042.    ++this->num_redo;
  2043.    }
  2044.  
  2045.  
  2046. static void PalTable__Redo(PalTable *this)
  2047.    {
  2048.    if ( this->num_redo <= 0 )
  2049.       return ;
  2050.  
  2051. #ifdef DEBUG_UNDO
  2052.    mprintf("%6ld Redo:", ftell(this->undo_file));
  2053. #endif
  2054.  
  2055.    fseek(this->undo_file, 0, SEEK_CUR);  /* to make sure we are in "read" mode */
  2056.    PalTable__UndoProcess(this, 1);
  2057.  
  2058.    --this->num_redo;
  2059.    }
  2060.  
  2061.  
  2062. /* - everything else - */
  2063.  
  2064.  
  2065. #define STATUS_LEN (4)
  2066.  
  2067. static void PalTable__DrawStatus(PalTable *this, BOOLEAN stripe_mode)
  2068.    {
  2069.    int width = 1+(this->csize*16)+1+1;
  2070.  
  2071.    if ( !this->hidden && ( width - (RGBEditor_WIDTH*2+4) >= STATUS_LEN*8 ) )
  2072.       {
  2073.       int x = this->x + 2 + RGBEditor_WIDTH,
  2074.           y = this->y + PalTable_PALY - 10;
  2075.  
  2076.       Cursor_Hide();
  2077.  
  2078.       displayc(x+(0*8), y, fg_color, bg_color, (this->auto_select) ? 'A' : 254);
  2079.       displayc(x+(1*8), y, fg_color, bg_color, (this->exclude==1)  ? 'X' :
  2080.                                                (this->exclude==2)  ? 'Y' : 254);
  2081.       displayc(x+(2*8), y, fg_color, bg_color, (this->freestyle)   ? 'F' : 254);
  2082.       displayc(x+(3*8), y, fg_color, bg_color, (stripe_mode)       ? 'T' : 254);
  2083.  
  2084.       Cursor_Show();
  2085.       }
  2086.    }
  2087.  
  2088.  
  2089. static void PalTable__HlPal(PalTable *this, int pnum, int color)
  2090.    {
  2091.    int x    = this->x + PalTable_PALX + (pnum%16)*this->csize,
  2092.        y    = this->y + PalTable_PALY + (pnum/16)*this->csize,
  2093.        size = this->csize;
  2094.  
  2095.    if (this->hidden)
  2096.       return ;
  2097.  
  2098.    Cursor_Hide();
  2099.  
  2100.    if (color < 0)
  2101.       drect(x, y, size+1, size+1);
  2102.    else
  2103.       rect(x, y, size+1, size+1, color);
  2104.  
  2105.    Cursor_Show();
  2106.    }
  2107.  
  2108.  
  2109. static void PalTable__Draw(PalTable *this)
  2110.    {
  2111.    int pal;
  2112.    int xoff, yoff;
  2113.    int width;
  2114.  
  2115.    if (this->hidden)
  2116.       return ;
  2117.  
  2118.    Cursor_Hide();
  2119.  
  2120.    width = 1+(this->csize*16)+1+1;
  2121.  
  2122.    rect(this->x, this->y, width, 2+RGBEditor_DEPTH+2+(this->csize*16)+1+1, fg_color);
  2123.  
  2124.    fillrect(this->x+1, this->y+1, width-2, 2+RGBEditor_DEPTH+2+(this->csize*16)+1+1-2, bg_color);
  2125.  
  2126.    hline(this->x, this->y+PalTable_PALY-1, width, fg_color);
  2127.  
  2128.    if ( width - (RGBEditor_WIDTH*2+4) >= TITLE_LEN*8 )
  2129.       {
  2130.       int center = (width - TITLE_LEN*8) / 2;
  2131.  
  2132.       displayf(this->x+center, this->y+2+RGBEditor_DEPTH/2-4, fg_color, bg_color, TITLE);
  2133.       }
  2134.  
  2135.    RGBEditor_Draw(this->rgb[0]);
  2136.    RGBEditor_Draw(this->rgb[1]);
  2137.  
  2138.    for (pal=0; pal<256; pal++)
  2139.       {
  2140.       xoff = PalTable_PALX + (pal%16) * this->csize;
  2141.       yoff = PalTable_PALY + (pal/16) * this->csize;
  2142.  
  2143.       if ( pal >= colors )
  2144.      {
  2145.      fillrect(this->x + xoff + 1, this->y + yoff + 1, this->csize-1, this->csize-1, bg_color);
  2146.      draw_diamond(this->x + xoff + this->csize/2 - 1, this->y + yoff + this->csize/2 - 1, fg_color);
  2147.      }
  2148.  
  2149.       else if ( is_reserved(pal) )
  2150.      {
  2151.      int x1 = this->x + xoff + 1,
  2152.          y1 = this->y + yoff + 1,
  2153.          x2 = x1 + this->csize - 2,
  2154.          y2 = y1 + this->csize - 2;
  2155.      fillrect(this->x + xoff + 1, this->y + yoff + 1, this->csize-1, this->csize-1, bg_color);
  2156.      draw_line(x1, y1, x2, y2, fg_color);
  2157.      draw_line(x1, y2, x2, y1, fg_color);
  2158.      }
  2159.       else
  2160.      fillrect(this->x + xoff + 1, this->y + yoff + 1, this->csize-1, this->csize-1, pal);
  2161.  
  2162.       }
  2163.  
  2164.    if (this->active == 0)
  2165.       {
  2166.       PalTable__HlPal(this, this->curr[1], -1);
  2167.       PalTable__HlPal(this, this->curr[0], fg_color);
  2168.       }
  2169.    else
  2170.       {
  2171.       PalTable__HlPal(this, this->curr[0], -1);
  2172.       PalTable__HlPal(this, this->curr[1], fg_color);
  2173.       }
  2174.  
  2175.    PalTable__DrawStatus(this, FALSE);
  2176.  
  2177.    Cursor_Show();
  2178.    }
  2179.  
  2180.  
  2181.  
  2182. static BOOLEAN PalTable__SetCurr(PalTable *this, int which, int curr)
  2183.    {
  2184.    BOOLEAN redraw = (BOOLEAN)((which < 0) ? TRUE : FALSE);
  2185.  
  2186.    if ( redraw )
  2187.       {
  2188.       which = this->active;
  2189.       curr = this->curr[which];
  2190.       }
  2191.    else
  2192.       if ( curr == this->curr[which] || curr < 0 )
  2193.      return (FALSE);
  2194.  
  2195.    Cursor_Hide();
  2196.  
  2197.    PalTable__HlPal(this, this->curr[0], bg_color);
  2198.    PalTable__HlPal(this, this->curr[1], bg_color);
  2199.    PalTable__HlPal(this, this->top,     bg_color);
  2200.    PalTable__HlPal(this, this->bottom,  bg_color);
  2201.  
  2202.    if ( this->freestyle )
  2203.       {
  2204.       this->curr[which] = curr;
  2205.  
  2206.       PalTable__CalcTopBottom(this);
  2207.  
  2208.       PalTable__HlPal(this, this->top,    -1);
  2209.       PalTable__HlPal(this, this->bottom, -1);
  2210.       PalTable__HlPal(this, this->curr[this->active], fg_color);
  2211.  
  2212.       RGBEditor_SetRGB(this->rgb[which], this->curr[which], &this->fs_color);
  2213.       RGBEditor_Update(this->rgb[which]);
  2214.  
  2215.       PalTable__UpdateDAC(this);
  2216.  
  2217.       Cursor_Show();
  2218.  
  2219.       return (TRUE);
  2220.       }
  2221.  
  2222.    this->curr[which] = curr;
  2223.  
  2224.    if (this->curr[0] != this->curr[1])
  2225.       PalTable__HlPal(this, this->curr[this->active==0?1:0], -1);
  2226.    PalTable__HlPal(this, this->curr[this->active], fg_color);
  2227.  
  2228.    RGBEditor_SetRGB(this->rgb[which], this->curr[which], &(this->pal[this->curr[which]]));
  2229.  
  2230.    if (redraw)
  2231.       {
  2232.       int other = (which==0) ? 1 : 0;
  2233.       RGBEditor_SetRGB(this->rgb[other], this->curr[other], &(this->pal[this->curr[other]]));
  2234.       RGBEditor_Update(this->rgb[0]);
  2235.       RGBEditor_Update(this->rgb[1]);
  2236.       }
  2237.    else
  2238.       RGBEditor_Update(this->rgb[which]);
  2239.  
  2240.    if (this->exclude)
  2241.       PalTable__UpdateDAC(this);
  2242.  
  2243.    Cursor_Show();
  2244.  
  2245.    this->curr_changed = FALSE;
  2246.  
  2247.    return(TRUE);
  2248.    }
  2249.  
  2250.  
  2251. static BOOLEAN PalTable__MemoryAlloc(PalTable *this, long size)
  2252.    {
  2253.    char far *temp;
  2254.  
  2255.    if (debugflag == 420)
  2256.       {
  2257.       this->stored_at = NOWHERE;
  2258.       return (FALSE);   /* can't do it */
  2259.       }
  2260.    temp = farmemalloc(FAR_RESERVE);   /* minimum free space */
  2261.  
  2262.    if (temp == NULL)
  2263.       {
  2264.       this->stored_at = NOWHERE;
  2265.       return (FALSE);   /* can't do it */
  2266.       }
  2267.  
  2268.    this->memory = farmemalloc( size );
  2269.  
  2270.    farmemfree(temp);
  2271.  
  2272.    if ( this->memory == NULL )
  2273.       {
  2274.       this->stored_at = NOWHERE;
  2275.       return (FALSE);
  2276.       }
  2277.    else
  2278.       {
  2279.       this->stored_at = MEMORY;
  2280.       return (TRUE);
  2281.       }
  2282.    }
  2283.  
  2284.  
  2285. static void PalTable__SaveRect(PalTable *this)
  2286.    {
  2287.    char buff[MAX_WIDTH];
  2288.    int  width = PalTable_PALX + this->csize*16 + 1 + 1,
  2289.         depth = PalTable_PALY + this->csize*16 + 1 + 1;
  2290.    int  yoff;
  2291.  
  2292.  
  2293.    /* first, do any de-allocationg */
  2294.  
  2295.    switch( this->stored_at )
  2296.       {
  2297.       case NOWHERE:
  2298.      break;
  2299.  
  2300.       case DISK:
  2301.      break;
  2302.  
  2303.       case MEMORY:
  2304.      if (this->memory != NULL)
  2305.         farmemfree(this->memory);
  2306.      this->memory = NULL;
  2307.      break;
  2308.       } ;
  2309.  
  2310.    /* allocate space and store the rect */
  2311.  
  2312.    if ( PalTable__MemoryAlloc(this, (long)width*depth) )
  2313.       {
  2314.       char far  *ptr = this->memory;
  2315.       char far  *bufptr = buff; /* MSC needs this indirection to get it right */
  2316.  
  2317.       Cursor_Hide();
  2318.       for (yoff=0; yoff<depth; yoff++)
  2319.      {
  2320.      getrow(this->x, this->y+yoff, width, buff);
  2321.      hline (this->x, this->y+yoff, width, bg_color);
  2322.      movedata(FP_SEG(bufptr), FP_OFF(bufptr), FP_SEG(ptr), FP_OFF(ptr), width);
  2323.      ptr = (char far *)normalize(ptr+width);
  2324.      }
  2325.       Cursor_Show();
  2326.       }
  2327.  
  2328.    else /* to disk */
  2329.       {
  2330.       this->stored_at = DISK;
  2331.  
  2332.       if ( this->file == NULL )
  2333.      {
  2334.      this->file = dir_fopen(tempdir,scrnfile, "w+b");
  2335.      if (this->file == NULL)
  2336.         {
  2337.         this->stored_at = NOWHERE;
  2338.         buzzer(3);
  2339.         return ;
  2340.         }
  2341.      }
  2342.  
  2343.       rewind(this->file);
  2344.       Cursor_Hide();
  2345.       for (yoff=0; yoff<depth; yoff++)
  2346.      {
  2347.      getrow(this->x, this->y+yoff, width, buff);
  2348.      hline (this->x, this->y+yoff, width, bg_color);
  2349.      if ( fwrite(buff, width, 1, this->file) != 1 )
  2350.         {
  2351.         buzzer(3);
  2352.         break;
  2353.         }
  2354.      }
  2355.       Cursor_Show();
  2356.       }
  2357.  
  2358.    }
  2359.  
  2360.  
  2361. static void PalTable__RestoreRect(PalTable *this)
  2362.    {
  2363.    char buff[MAX_WIDTH];
  2364.    int  width = PalTable_PALX + this->csize*16 + 1 + 1,
  2365.         depth = PalTable_PALY + this->csize*16 + 1 + 1;
  2366.    int  yoff;
  2367.  
  2368.    if (this->hidden)
  2369.       return;
  2370.  
  2371.    switch ( this->stored_at )
  2372.       {
  2373.       case DISK:
  2374.      rewind(this->file);
  2375.      Cursor_Hide();
  2376.      for (yoff=0; yoff<depth; yoff++)
  2377.         {
  2378.         if ( fread(buff, width, 1, this->file) != 1 )
  2379.            {
  2380.            buzzer(3);
  2381.            break;
  2382.            }
  2383.         putrow(this->x, this->y+yoff, width, buff);
  2384.         }
  2385.      Cursor_Show();
  2386.      break;
  2387.  
  2388.       case MEMORY:
  2389.      {
  2390.      char far  *ptr = this->memory;
  2391.      char far  *bufptr = buff; /* MSC needs this indirection to get it right */
  2392.  
  2393.      Cursor_Hide();
  2394.      for (yoff=0; yoff<depth; yoff++)
  2395.         {
  2396.         movedata(FP_SEG(ptr), FP_OFF(ptr), FP_SEG(bufptr), FP_OFF(bufptr), width);
  2397.         putrow(this->x, this->y+yoff, width, buff);
  2398.         ptr = (char far *)normalize(ptr+width);
  2399.         }
  2400.      Cursor_Show();
  2401.      break;
  2402.      }
  2403.  
  2404.       case NOWHERE:
  2405.      break;
  2406.       } /* switch */
  2407.    }
  2408.  
  2409.  
  2410. static void PalTable__SetPos(PalTable *this, int x, int y)
  2411.    {
  2412.    int width = PalTable_PALX + this->csize*16 + 1 + 1;
  2413.  
  2414.    this->x = x;
  2415.    this->y = y;
  2416.  
  2417.    RGBEditor_SetPos(this->rgb[0], x+2, y+2);
  2418.    RGBEditor_SetPos(this->rgb[1], x+width-2-RGBEditor_WIDTH, y+2);
  2419.    }
  2420.  
  2421.  
  2422. static void PalTable__SetCSize(PalTable *this, int csize)
  2423.    {
  2424.    this->csize = csize;
  2425.    PalTable__SetPos(this, this->x, this->y);
  2426.    }
  2427.  
  2428.  
  2429. static int PalTable__GetCursorColor(PalTable *this)
  2430.    {
  2431.    int x     = Cursor_GetX(),
  2432.        y     = Cursor_GetY(),
  2433.        size;
  2434.    int color = getcolor(x, y);
  2435.  
  2436.    if ( is_reserved(color) )
  2437.       {
  2438.       if ( is_in_box(x, y, this->x, this->y, 1+(this->csize*16)+1+1, 2+RGBEditor_DEPTH+2+(this->csize*16)+1+1) )
  2439.      {  /* is the cursor over the editor? */
  2440.      x -= this->x + PalTable_PALX;
  2441.      y -= this->y + PalTable_PALY;
  2442.      size = this->csize;
  2443.  
  2444.      if (x < 0 || y < 0 || x > size*16 || y > size*16)
  2445.         return (-1);
  2446.  
  2447.      if ( x == size*16 )
  2448.         --x;
  2449.      if ( y == size*16 )
  2450.         --y;
  2451.  
  2452.      return ( (y/size)*16 + x/size );
  2453.      }
  2454.       else
  2455.      return (color);
  2456.       }
  2457.  
  2458.    return (color);
  2459.    }
  2460.  
  2461.  
  2462.  
  2463. #define CURS_INC 1
  2464.  
  2465. static void PalTable__DoCurs(PalTable *this, int key)
  2466.    {
  2467.    BOOLEAN done  = FALSE;
  2468.    BOOLEAN first = TRUE;
  2469.    int       xoff  = 0,
  2470.        yoff  = 0;
  2471.  
  2472.    while ( !done )
  2473.       {
  2474.       switch(key)
  2475.      {
  2476.      case RIGHT_ARROW_2:     xoff += CURS_INC*4;   break;
  2477.      case RIGHT_ARROW:     xoff += CURS_INC;     break;
  2478.      case LEFT_ARROW_2:     xoff -= CURS_INC*4;   break;
  2479.      case LEFT_ARROW:     xoff -= CURS_INC;     break;
  2480.      case DOWN_ARROW_2:     yoff += CURS_INC*4;   break;
  2481.      case DOWN_ARROW:     yoff += CURS_INC;     break;
  2482.      case UP_ARROW_2:     yoff -= CURS_INC*4;   break;
  2483.      case UP_ARROW:      yoff -= CURS_INC;     break;
  2484.  
  2485.      default:
  2486.         done = TRUE;
  2487.      }
  2488.  
  2489.       if (!done)
  2490.      {
  2491.      if (!first)
  2492.         getakey();         /* delete key from buffer */
  2493.      else
  2494.         first = FALSE;
  2495.      key = keypressed();   /* peek at the next one... */
  2496.      }
  2497.       }
  2498.  
  2499.    Cursor_Move(xoff, yoff);
  2500.  
  2501.    if (this->auto_select)
  2502.       PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
  2503.    }
  2504.  
  2505.  
  2506. #ifdef __TURBOC__
  2507. #   pragma argsused
  2508. #endif
  2509. #ifdef __CLINT__
  2510. #   pragma argsused
  2511. #endif
  2512.  
  2513. static void PalTable__change(RGBEditor *rgb, VOIDPTR info)
  2514.    {
  2515.    PalTable *this = (PalTable *)info;
  2516.    int       pnum = this->curr[this->active];
  2517.  
  2518.    if ( this->freestyle )
  2519.       {
  2520.       this->fs_color = RGBEditor_GetRGB(rgb);
  2521.       PalTable__UpdateDAC(this);
  2522.       return ;
  2523.       }
  2524.  
  2525.    if ( !this->curr_changed )
  2526.       {
  2527.       PalTable__SaveUndoData(this, pnum, pnum);
  2528.       this->curr_changed = TRUE;
  2529.       }
  2530.  
  2531.    this->pal[pnum] = RGBEditor_GetRGB(rgb);
  2532.  
  2533.    if (this->curr[0] == this->curr[1])
  2534.       {
  2535.       int      other = this->active==0 ? 1 : 0;
  2536.       PALENTRY color;
  2537.  
  2538.       color = RGBEditor_GetRGB(this->rgb[this->active]);
  2539.       RGBEditor_SetRGB(this->rgb[other], this->curr[other], &color);
  2540.  
  2541.       Cursor_Hide();
  2542.       RGBEditor_Update(this->rgb[other]);
  2543.       Cursor_Show();
  2544.       }
  2545.  
  2546.    }
  2547.  
  2548.  
  2549. static void PalTable__UpdateDAC(PalTable *this)
  2550.    {
  2551.    if ( this->exclude )
  2552.       {
  2553.       memset(dacbox, 0, 256*3);
  2554.       if (this->exclude == 1)
  2555.      {
  2556.      int a = this->curr[this->active];
  2557.      memmove(dacbox[a], &this->pal[a], 3);
  2558.      }
  2559.       else
  2560.      {
  2561.      int a = this->curr[0],
  2562.          b = this->curr[1];
  2563.  
  2564.      if (a>b)
  2565.         {
  2566.         int t=a;
  2567.         a=b;
  2568.         b=t;
  2569.         }
  2570.  
  2571.      memmove(dacbox[a], &this->pal[a], 3*(1+(b-a)));
  2572.      }
  2573.       }
  2574.    else
  2575.       {
  2576.       memmove(dacbox[0], this->pal, 3*colors);
  2577.  
  2578.       if ( this->freestyle )
  2579.          PalTable__PutBand(this, (PALENTRY *)dacbox);   /* apply band to dacbox */
  2580.       }
  2581.  
  2582.    if ( !this->hidden )
  2583.       {
  2584.       if (inverse)
  2585.      {
  2586.      memset(dacbox[fg_color], 0, 3);     /* dacbox[fg] = (0,0,0) */
  2587.      memset(dacbox[bg_color], 48, 3);     /* dacbox[bg] = (48,48,48) */
  2588.      }
  2589.       else
  2590.      {
  2591.      memset(dacbox[bg_color], 0, 3);     /* dacbox[bg] = (0,0,0) */
  2592.      memset(dacbox[fg_color], 48, 3);     /* dacbox[fg] = (48,48,48) */
  2593.      }
  2594.       }
  2595.  
  2596.    spindac(0,1);
  2597.    }
  2598.  
  2599.  
  2600. static void PalTable__Rotate(PalTable *this, int dir, int lo, int hi)
  2601.    {
  2602.  
  2603.    rotatepal(this->pal, dir, lo, hi);
  2604.  
  2605.    Cursor_Hide();
  2606.  
  2607.    /* update the DAC.  */
  2608.  
  2609.    PalTable__UpdateDAC(this);
  2610.  
  2611.    /* update the editors. */
  2612.  
  2613.    RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]]));
  2614.    RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]]));
  2615.    RGBEditor_Update(this->rgb[0]);
  2616.    RGBEditor_Update(this->rgb[1]);
  2617.  
  2618.    Cursor_Show();
  2619.    }
  2620.  
  2621.  
  2622. static void PalTable__other_key(int key, RGBEditor *rgb, VOIDPTR info)
  2623.    {
  2624.    PalTable *this = (PalTable *)info;
  2625.  
  2626.    switch(key)
  2627.       {
  2628.       case '\\':    /* move/resize */
  2629.      {
  2630.      if (this->hidden)
  2631.         break;         /* cannot move a hidden pal */
  2632.      Cursor_Hide();
  2633.      PalTable__RestoreRect(this);
  2634.      MoveBox_SetPos(this->movebox, this->x, this->y);
  2635.      MoveBox_SetCSize(this->movebox, this->csize);
  2636.      if ( MoveBox_Process(this->movebox) )
  2637.         {
  2638.         if ( MoveBox_ShouldHide(this->movebox) )
  2639.            PalTable_SetHidden(this, TRUE);
  2640.         else if ( MoveBox_Moved(this->movebox) )
  2641.            {
  2642.            PalTable__SetPos(this, MoveBox_X(this->movebox), MoveBox_Y(this->movebox));
  2643.            PalTable__SetCSize(this, MoveBox_CSize(this->movebox));
  2644.            PalTable__SaveRect(this);
  2645.            }
  2646.         }
  2647.      PalTable__Draw(this);
  2648.      Cursor_Show();
  2649.  
  2650.      RGBEditor_SetDone(this->rgb[this->active], TRUE);
  2651.  
  2652.      if (this->auto_select)
  2653.         PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
  2654.      break;
  2655.      }
  2656.  
  2657.       case 'Y':    /* exclude range */
  2658.       case 'y':
  2659.      if ( this->exclude==2 )
  2660.         this->exclude = 0;
  2661.      else
  2662.         this->exclude = 2;
  2663.      PalTable__UpdateDAC(this);
  2664.          PalTable__DrawStatus(this, FALSE);
  2665.      break;
  2666.  
  2667.       case 'X':
  2668.       case 'x':     /* exclude current entry */
  2669.      if ( this->exclude==1 )
  2670.         this->exclude = 0;
  2671.      else
  2672.         this->exclude = 1;
  2673.      PalTable__UpdateDAC(this);
  2674.          PalTable__DrawStatus(this, FALSE);
  2675.      break;
  2676.  
  2677.       case RIGHT_ARROW:
  2678.       case LEFT_ARROW:
  2679.       case UP_ARROW:
  2680.       case DOWN_ARROW:
  2681.       case RIGHT_ARROW_2:
  2682.       case LEFT_ARROW_2:
  2683.       case UP_ARROW_2:
  2684.       case DOWN_ARROW_2:
  2685.      PalTable__DoCurs(this, key);
  2686.      break;
  2687.  
  2688.       case ESC:
  2689.      this->done = TRUE;
  2690.      RGBEditor_SetDone(rgb, TRUE);
  2691.      break;
  2692.  
  2693.       case ' ':     /* select the other palette register */
  2694.      this->active = (this->active==0) ? 1 : 0;
  2695.      if (this->auto_select)
  2696.         PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
  2697.       else
  2698.         PalTable__SetCurr(this, -1, 0);
  2699.  
  2700.      if (this->exclude || this->freestyle)
  2701.         PalTable__UpdateDAC(this);
  2702.  
  2703.      RGBEditor_SetDone(rgb, TRUE);
  2704.      break;
  2705.  
  2706.       case ENTER:    /* set register to color under cursor.  useful when not */
  2707.       case ENTER_2:  /* in auto_select mode */
  2708.  
  2709.          if ( this->freestyle )
  2710.             {
  2711.             PalTable__SaveUndoData(this, this->bottom, this->top);
  2712.             PalTable__PutBand(this, this->pal);
  2713.             }
  2714.  
  2715.      PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
  2716.  
  2717.      if (this->exclude || this->freestyle )
  2718.         PalTable__UpdateDAC(this);
  2719.  
  2720.      RGBEditor_SetDone(rgb, TRUE);
  2721.      break;
  2722.  
  2723.       case 'D':    /* copy (Duplicate?) color in inactive to color in active */
  2724.       case 'd':
  2725.      {
  2726.      int   a = this->active,
  2727.           b = (a==0) ? 1 : 0;
  2728.      PALENTRY t;
  2729.  
  2730.      t = RGBEditor_GetRGB(this->rgb[b]);
  2731.      Cursor_Hide();
  2732.  
  2733.      RGBEditor_SetRGB(this->rgb[a], this->curr[a], &t);
  2734.      RGBEditor_Update(this->rgb[a]);
  2735.      PalTable__change(this->rgb[a], this);
  2736.      PalTable__UpdateDAC(this);
  2737.  
  2738.      Cursor_Show();
  2739.      break;
  2740.      }
  2741.  
  2742.       case '=':    /* create a shade range between the two entries */
  2743.      {
  2744.      int a = this->curr[0],
  2745.          b = this->curr[1];
  2746.  
  2747.      if (a > b)
  2748.         {
  2749.         int t = a;
  2750.         a = b;
  2751.         b = t;
  2752.         }
  2753.  
  2754.          PalTable__SaveUndoData(this, a, b);
  2755.  
  2756.      if (a != b)
  2757.         {
  2758.         mkpalrange(&this->pal[a], &this->pal[b], &this->pal[a], b-a, 1);
  2759.         PalTable__UpdateDAC(this);
  2760.         }
  2761.  
  2762.      break;
  2763.      }
  2764.  
  2765.       case '!':    /* swap r<->g */
  2766.      {
  2767.      int a = this->curr[0],
  2768.          b = this->curr[1];
  2769.  
  2770.      if (a > b)
  2771.         {
  2772.         int t = a;
  2773.         a = b;
  2774.         b = t;
  2775.         }
  2776.  
  2777.          PalTable__SaveUndoData(this, a, b);
  2778.  
  2779.      if (a != b)
  2780.         {
  2781.         rotcolrg(&this->pal[a], b-a);
  2782.         PalTable__UpdateDAC(this);
  2783.         }
  2784.  
  2785.  
  2786.      break;
  2787.      }
  2788.  
  2789.       case '@':    /* swap g<->b */
  2790.      {
  2791.      int a = this->curr[0],
  2792.          b = this->curr[1];
  2793.  
  2794.      if (a > b)
  2795.         {
  2796.         int t = a;
  2797.         a = b;
  2798.         b = t;
  2799.         }
  2800.  
  2801.          PalTable__SaveUndoData(this, a, b);
  2802.  
  2803.      if (a != b)
  2804.         {
  2805.         rotcolgb(&this->pal[a], b-a);
  2806.         PalTable__UpdateDAC(this);
  2807.         }
  2808.  
  2809.      break;
  2810.      }
  2811.  
  2812.       case '#':    /* swap r<->b */
  2813.      {
  2814.      int a = this->curr[0],
  2815.          b = this->curr[1];
  2816.  
  2817.      if (a > b)
  2818.         {
  2819.         int t = a;
  2820.         a = b;
  2821.         b = t;
  2822.         }
  2823.  
  2824.          PalTable__SaveUndoData(this, a, b);
  2825.  
  2826.      if (a != b)
  2827.         {
  2828.         rotcolbr(&this->pal[a], b-a);
  2829.         PalTable__UpdateDAC(this);
  2830.         }
  2831.  
  2832.      break;
  2833.      }
  2834.  
  2835.  
  2836.       case 'T':
  2837.       case 't':   /* s(T)ripe mode */
  2838.      {
  2839.      int key;
  2840.  
  2841.      Cursor_Hide();
  2842.          PalTable__DrawStatus(this, TRUE);
  2843.      key = getakeynohelp();
  2844.          PalTable__DrawStatus(this, FALSE);
  2845.      Cursor_Show();
  2846.  
  2847.      if (key >= '1' && key <= '9')
  2848.         {
  2849.         int a = this->curr[0],
  2850.         b = this->curr[1];
  2851.  
  2852.         if (a > b)
  2853.            {
  2854.            int t = a;
  2855.            a = b;
  2856.            b = t;
  2857.            }
  2858.  
  2859.             PalTable__SaveUndoData(this, a, b);
  2860.  
  2861.         if (a != b)
  2862.            {
  2863.            mkpalrange(&this->pal[a], &this->pal[b], &this->pal[a], b-a, key-'0');
  2864.            PalTable__UpdateDAC(this);
  2865.            }
  2866.         }
  2867.  
  2868.      break;
  2869.      }
  2870.  
  2871.       case 'M':   /* set gamma */
  2872.       case 'm':
  2873.       {
  2874.           static FCODE o_msg[] = {"Enter gamma value"};
  2875.           char msg[sizeof(o_msg)];
  2876.           int i;
  2877.           char buf[20];
  2878.           far_strcpy(msg,o_msg);
  2879.           sprintf(buf,"%.3f",1./gamma_val);
  2880.           stackscreen();
  2881.           i = field_prompt(0,msg,NULL,buf,20,NULL);
  2882.           unstackscreen();
  2883.           if (i != -1) {
  2884.           sscanf(buf,"%f",&gamma_val);
  2885.           if (gamma_val==0) {
  2886.               gamma_val = (float)0.0000000001;
  2887.           }
  2888.           gamma_val = (float)(1./gamma_val);
  2889.           }
  2890.       }
  2891.       break;
  2892.       case 'A':   /* toggle auto-select mode */
  2893.       case 'a':
  2894.      this->auto_select = (BOOLEAN)((this->auto_select) ? FALSE : TRUE);
  2895.      if (this->auto_select)
  2896.         {
  2897.         PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
  2898.         if (this->exclude)
  2899.            PalTable__UpdateDAC(this);
  2900.         }
  2901.          PalTable__DrawStatus(this, FALSE);
  2902.      break;
  2903.  
  2904.       case 'H':
  2905.       case 'h': /* toggle hide/display of palette editor */
  2906.      Cursor_Hide();
  2907.      PalTable_Hide(this, rgb, (BOOLEAN)((this->hidden) ? FALSE : TRUE));
  2908.      Cursor_Show();
  2909.      break;
  2910.  
  2911.       case '.':   /* rotate once */
  2912.       case ',':
  2913.      {
  2914.          int dir = (key=='.') ? 1 : -1;
  2915.  
  2916.          PalTable__SaveUndoRotate(this, dir, rotate_lo, rotate_hi);
  2917.      PalTable__Rotate(this, dir, rotate_lo, rotate_hi);
  2918.      break;
  2919.      }
  2920.  
  2921.       case '>':   /* continuous rotation (until a key is pressed) */
  2922.       case '<':
  2923.      {
  2924.          int  dir;
  2925.      long tick;
  2926.          int  diff = 0;
  2927.  
  2928.      Cursor_Hide();
  2929.  
  2930.      if ( !this->hidden )
  2931.         {
  2932.         RGBEditor_BlankSampleBox(this->rgb[0]);
  2933.         RGBEditor_BlankSampleBox(this->rgb[1]);
  2934.         RGBEditor_SetHidden(this->rgb[0], TRUE);
  2935.         RGBEditor_SetHidden(this->rgb[1], TRUE);
  2936.         }
  2937.  
  2938.          do
  2939.             {
  2940.             dir = (key=='>') ? 1 : -1;
  2941.  
  2942.            while ( !keypressed() )
  2943.            {
  2944.            tick = readticker();
  2945.            PalTable__Rotate(this, dir, rotate_lo, rotate_hi);
  2946.                diff += dir;
  2947.            while (readticker() == tick) ;   /* wait until a tick passes */
  2948.            }
  2949.  
  2950.           key = getakey();
  2951.             }
  2952.          while (key=='<' || key=='>');
  2953.  
  2954.      if ( !this->hidden )
  2955.         {
  2956.         RGBEditor_SetHidden(this->rgb[0], FALSE);
  2957.         RGBEditor_SetHidden(this->rgb[1], FALSE);
  2958.         RGBEditor_Update(this->rgb[0]);
  2959.         RGBEditor_Update(this->rgb[1]);
  2960.         }
  2961.  
  2962.          if ( diff != 0 )
  2963.             PalTable__SaveUndoRotate(this, diff, rotate_lo, rotate_hi);
  2964.  
  2965.      Cursor_Show();
  2966.      break;
  2967.      }
  2968.  
  2969.       case 'I':     /* invert the fg & bg colors */
  2970.       case 'i':
  2971.     inverse = (BOOLEAN)!inverse;
  2972.     PalTable__UpdateDAC(this);
  2973.     break;
  2974.  
  2975.       case 'V':
  2976.       case 'v':     /* set the reserved colors to the editor colors */
  2977.      if ( this->curr[0] >= colors || this->curr[1] >= colors ||
  2978.           this->curr[0] == this->curr[1] )
  2979.         {
  2980.         buzzer(2);
  2981.         break;
  2982.         }
  2983.  
  2984.      fg_color = (BYTE)this->curr[0];
  2985.      bg_color = (BYTE)this->curr[1];
  2986.  
  2987.      if ( !this->hidden )
  2988.         {
  2989.         Cursor_Hide();
  2990.         PalTable__UpdateDAC(this);
  2991.         PalTable__Draw(this);
  2992.         Cursor_Show();
  2993.         }
  2994.  
  2995.      RGBEditor_SetDone(this->rgb[this->active], TRUE);
  2996.      break;
  2997.  
  2998.       case 'O':    /* set rotate_lo and rotate_hi to editors */
  2999.       case 'o':
  3000.      if (this->curr[0] > this->curr[1])
  3001.         {
  3002.         rotate_lo = this->curr[1];
  3003.         rotate_hi = this->curr[0];
  3004.         }
  3005.      else
  3006.         {
  3007.         rotate_lo = this->curr[0];
  3008.         rotate_hi = this->curr[1];
  3009.         }
  3010.      break;
  3011.  
  3012.       case F2:      /* restore a palette */
  3013.       case F3:
  3014.       case F4:
  3015.       case F5:
  3016.       case F6:
  3017.       case F7:
  3018.       case F8:
  3019.       case F9:
  3020.      {
  3021.      int which = key - F2;
  3022.  
  3023.      if ( this->save_pal[which] != NULL )
  3024.         {
  3025.         struct SREGS seg;
  3026.  
  3027.         Cursor_Hide();
  3028.  
  3029.             PalTable__SaveUndoData(this, 0, 255);
  3030.  
  3031.         segread(&seg);
  3032.         movedata(FP_SEG(this->save_pal[which]), FP_OFF(this->save_pal[which]),
  3033.              seg.ds, (USEGTYPE)(this->pal), 256*3);
  3034.  
  3035.         PalTable__UpdateDAC(this);
  3036.  
  3037.         PalTable__SetCurr(this, -1, 0);
  3038.         Cursor_Show();
  3039.         RGBEditor_SetDone(this->rgb[this->active], TRUE);
  3040.         }
  3041.      else
  3042.         buzzer(3);     /* error buzz */
  3043.      break;
  3044.      }
  3045.  
  3046.       case SF2:   /* save a palette */
  3047.       case SF3:
  3048.       case SF4:
  3049.       case SF5:
  3050.       case SF6:
  3051.       case SF7:
  3052.       case SF8:
  3053.       case SF9:
  3054.      {
  3055.      int which = key - SF2;
  3056.  
  3057.      if ( this->save_pal[which] != NULL )
  3058.         {
  3059.         struct SREGS seg;
  3060.  
  3061.         segread(&seg);
  3062.         movedata(seg.ds, (USEGTYPE)(this->pal), FP_SEG(this->save_pal[which]),
  3063.             FP_OFF(this->save_pal[which]), 256*3);
  3064.         }
  3065.      else
  3066.         buzzer(3); /* oops! short on memory! */
  3067.      break;
  3068.      }
  3069.  
  3070.       case 'L':     /* load a .map palette */
  3071.       case 'l':
  3072.      {
  3073.          PalTable__SaveUndoData(this, 0, 255);
  3074.  
  3075.      load_palette();
  3076. #ifndef XFRACT
  3077.      getpalrange(0, colors, this->pal);
  3078. #else
  3079.      getpalrange(0, 256, this->pal);
  3080. #endif
  3081.      PalTable__UpdateDAC(this);
  3082.      RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]]));
  3083.      RGBEditor_Update(this->rgb[0]);
  3084.      RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]]));
  3085.      RGBEditor_Update(this->rgb[1]);
  3086.      break;
  3087.      }
  3088.  
  3089.       case 'S':     /* save a .map palette */
  3090.       case 's':
  3091.      {
  3092. #ifndef XFRACT
  3093.      setpalrange(0, colors, this->pal);
  3094. #else
  3095.      setpalrange(0, 256, this->pal);
  3096. #endif
  3097.      save_palette();
  3098.      PalTable__UpdateDAC(this);
  3099.      break;
  3100.      }
  3101.  
  3102.       case 'C':     /* color cycling sub-mode */
  3103.       case 'c':
  3104.      {
  3105.      BOOLEAN oldhidden = (BOOLEAN)this->hidden;
  3106.  
  3107.          PalTable__SaveUndoData(this, 0, 255);
  3108.  
  3109.      Cursor_Hide();
  3110.      if ( !oldhidden )
  3111.         PalTable_Hide(this, rgb, TRUE);
  3112.      setpalrange(0, colors, this->pal);
  3113.      rotate(0);
  3114.      getpalrange(0, colors, this->pal);
  3115.      PalTable__UpdateDAC(this);
  3116.      if ( !oldhidden )
  3117.         {
  3118.         RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]]));
  3119.         RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]]));
  3120.         PalTable_Hide(this, rgb, FALSE);
  3121.         }
  3122.      Cursor_Show();
  3123.      break;
  3124.      }
  3125.  
  3126.       case 'F':
  3127.       case 'f':    /* toggle freestyle palette edit mode */
  3128.          this->freestyle= (BOOLEAN)((this->freestyle) ? FALSE :TRUE);
  3129.  
  3130.          PalTable__SetCurr(this, -1, 0);
  3131.  
  3132.          if ( !this->freestyle )   /* if turning off... */
  3133.             PalTable__UpdateDAC(this);
  3134.  
  3135.          PalTable__DrawStatus(this, FALSE);
  3136.          break;
  3137.  
  3138.       case CTL_DEL:  /* rt plus down */
  3139.          if (this->bandwidth >0 )
  3140.             this->bandwidth  --;
  3141.          else
  3142.             this->bandwidth=0;
  3143.          PalTable__SetCurr(this, -1, 0);
  3144.          break;
  3145.  
  3146.       case CTL_INSERT: /* rt plus up */
  3147.          if (this->bandwidth <255 )
  3148.            this->bandwidth ++;
  3149.          else
  3150.             this->bandwidth = 255;
  3151.          PalTable__SetCurr(this, -1, 0);
  3152.          break;
  3153.  
  3154.       case 'W':   /* convert to greyscale */
  3155.       case 'w':
  3156.      {
  3157.      switch ( this->exclude )
  3158.         {
  3159.         case 0:   /* normal mode.  convert all colors to grey scale */
  3160.                PalTable__SaveUndoData(this, 0, 255);
  3161.            palrangetogrey(this->pal, 0, 256);
  3162.            break;
  3163.  
  3164.         case 1:   /* 'x' mode. convert current color to grey scale.  */
  3165.                PalTable__SaveUndoData(this, this->curr[this->active], this->curr[this->active]);
  3166.            palrangetogrey(this->pal, this->curr[this->active], 1);
  3167.            break;
  3168.  
  3169.         case 2:  /* 'y' mode.  convert range between editors to grey. */
  3170.            {
  3171.            int a = this->curr[0],
  3172.            b = this->curr[1];
  3173.  
  3174.            if (a > b)
  3175.           {
  3176.           int t = a;
  3177.           a = b;
  3178.           b = t;
  3179.           }
  3180.  
  3181.                PalTable__SaveUndoData(this, a, b);
  3182.            palrangetogrey(this->pal, a, 1+(b-a));
  3183.            break;
  3184.            }
  3185.         }
  3186.  
  3187.      PalTable__UpdateDAC(this);
  3188.      RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]]));
  3189.      RGBEditor_Update(this->rgb[0]);
  3190.      RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]]));
  3191.      RGBEditor_Update(this->rgb[1]);
  3192.      break;
  3193.      }
  3194.  
  3195.       case 'N':   /* convert to negative color */
  3196.       case 'n':
  3197.      {
  3198.      switch ( this->exclude )
  3199.         {
  3200.         case 0:     /* normal mode.  convert all colors to grey scale */
  3201.                PalTable__SaveUndoData(this, 0, 255);
  3202.            palrangetonegative(this->pal, 0, 256);
  3203.            break;
  3204.  
  3205.         case 1:     /* 'x' mode. convert current color to grey scale.  */
  3206.                PalTable__SaveUndoData(this, this->curr[this->active], this->curr[this->active]);
  3207.            palrangetonegative(this->pal, this->curr[this->active], 1);
  3208.            break;
  3209.  
  3210.         case 2:  /* 'y' mode.  convert range between editors to grey. */
  3211.            {
  3212.            int a = this->curr[0],
  3213.            b = this->curr[1];
  3214.  
  3215.            if (a > b)
  3216.           {
  3217.           int t = a;
  3218.           a = b;
  3219.           b = t;
  3220.           }
  3221.  
  3222.                PalTable__SaveUndoData(this, a, b);
  3223.            palrangetonegative(this->pal, a, 1+(b-a));
  3224.            break;
  3225.            }
  3226.         }
  3227.  
  3228.      PalTable__UpdateDAC(this);
  3229.      RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]]));
  3230.      RGBEditor_Update(this->rgb[0]);
  3231.      RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]]));
  3232.      RGBEditor_Update(this->rgb[1]);
  3233.      break;
  3234.      }
  3235.  
  3236.       case 'U':     /* Undo */
  3237.       case 'u':
  3238.          PalTable__Undo(this);
  3239.          break;
  3240.  
  3241.       case 'e':    /* Redo */
  3242.       case 'E':
  3243.          PalTable__Redo(this);
  3244.          break;
  3245.  
  3246.       } /* switch */
  3247.    }
  3248.  
  3249.  
  3250. static void PalTable__MkDefaultPalettes(PalTable *this)  /* creates default Fkey palettes */
  3251.    {
  3252.    PALENTRY     black,
  3253.             white;
  3254.    PALENTRY     temp[256];
  3255.    int            ctr;
  3256.    struct SREGS seg;
  3257.  
  3258.    black.red = black.green = black.blue = 0;
  3259.    white.red = white.green = white.blue = 63;
  3260.    mkpalrange(&black, &white, temp, 256, 1); /* boring! */
  3261.  
  3262.    segread(&seg);
  3263.  
  3264.    for (ctr=0; ctr<8; ctr++)   /* copy temp into all fkey saves */
  3265.       movedata(seg.ss, (USEGTYPE)(temp), FP_SEG(this->save_pal[ctr]),
  3266.            FP_OFF(this->save_pal[ctr]), 256*3);
  3267.    }
  3268.  
  3269.  
  3270.  
  3271. static PalTable *PalTable_Construct(void)
  3272.    {
  3273.    PalTable     *this = new(PalTable);
  3274.    int         csize;
  3275.    int         ctr;
  3276.    PALENTRY far *mem_block;
  3277.    void far     *temp;
  3278.  
  3279.    temp = farmemalloc(FAR_RESERVE);
  3280.  
  3281.    if ( temp != NULL )
  3282.       {
  3283.       mem_block = (PALENTRY far *)farmemalloc(256L*3 * 8);
  3284.  
  3285.       if ( mem_block == NULL )
  3286.      {
  3287.      for (ctr=0; ctr<8; ctr++)
  3288.         this->save_pal[ctr] = NULL;
  3289.      }
  3290.       else
  3291.      {
  3292.      for (ctr=0; ctr<8; ctr++)
  3293.         this->save_pal[ctr] = mem_block + (256*ctr);
  3294.  
  3295.      PalTable__MkDefaultPalettes(this);
  3296.      }
  3297.       farmemfree(temp);
  3298.       }
  3299.  
  3300.    this->rgb[0] = RGBEditor_Construct(0, 0, PalTable__other_key,
  3301.           PalTable__change, this);
  3302.    this->rgb[1] = RGBEditor_Construct(0, 0, PalTable__other_key,
  3303.           PalTable__change, this);
  3304.  
  3305.    this->movebox = MoveBox_Construct(0,0,0, PalTable_PALX+1, PalTable_PALY+1);
  3306.  
  3307.    this->active      = 0;
  3308.    this->curr[0]     = 1;
  3309.    this->curr[1]     = 1;
  3310.    this->auto_select = TRUE;
  3311.    this->exclude     = FALSE;
  3312.    this->hidden      = FALSE;
  3313.    this->stored_at   = NOWHERE;
  3314.    this->file         = NULL;
  3315.    this->memory      = NULL;
  3316.  
  3317.    this->fs_color.red   = 42;
  3318.    this->fs_color.green = 42;
  3319.    this->fs_color.blue  = 42;
  3320.    this->freestyle      = FALSE;
  3321.    this->bandwidth      = 15;
  3322.    this->top            = 255;
  3323.    this->bottom         = 0 ;
  3324.  
  3325.    this->undo_file    = dir_fopen(tempdir,undofile, "w+b");
  3326.    this->curr_changed = FALSE;
  3327.    this->num_redo     = 0;
  3328.  
  3329.    RGBEditor_SetRGB(this->rgb[0], this->curr[0], &this->pal[this->curr[0]]);
  3330.    RGBEditor_SetRGB(this->rgb[1], this->curr[1], &this->pal[this->curr[0]]);
  3331.  
  3332.    PalTable__SetPos(this, 0, 0);
  3333.  
  3334.    csize = ( (sydots-(PalTable_PALY+1+1)) / 2 ) / 16;
  3335.    if (csize<CSIZE_MIN)
  3336.       csize = CSIZE_MIN;
  3337.    PalTable__SetCSize(this, csize);
  3338.  
  3339.    return(this);
  3340.    }
  3341.  
  3342.  
  3343. static void PalTable_SetHidden(PalTable *this, BOOLEAN hidden)
  3344.    {
  3345.    this->hidden = hidden;
  3346.    RGBEditor_SetHidden(this->rgb[0], hidden);
  3347.    RGBEditor_SetHidden(this->rgb[1], hidden);
  3348.    PalTable__UpdateDAC(this);
  3349.    }
  3350.  
  3351.  
  3352.  
  3353. static void PalTable_Hide(PalTable *this, RGBEditor *rgb, BOOLEAN hidden)
  3354.    {
  3355.    if (hidden)
  3356.       {
  3357.       PalTable__RestoreRect(this);
  3358.       PalTable_SetHidden(this, TRUE);
  3359.       reserve_colors = FALSE;
  3360.       if (this->auto_select)
  3361.      PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
  3362.       }
  3363.    else
  3364.       {
  3365.       PalTable_SetHidden(this, FALSE);
  3366.       reserve_colors = TRUE;
  3367.       if (this->stored_at == NOWHERE)  /* do we need to save screen? */
  3368.      PalTable__SaveRect(this);
  3369.       PalTable__Draw(this);
  3370.       if (this->auto_select)
  3371.      PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
  3372.       RGBEditor_SetDone(rgb, TRUE);
  3373.       }
  3374.    }
  3375.  
  3376.  
  3377. static void PalTable_Destroy(PalTable *this)
  3378.    {
  3379.  
  3380.    if (this->file != NULL)
  3381.       {
  3382.       fclose(this->file);
  3383.       dir_remove(tempdir,scrnfile);
  3384.       }
  3385.  
  3386.    if (this->undo_file != NULL)
  3387.       {
  3388.       fclose(this->undo_file);
  3389.       dir_remove(tempdir,undofile);
  3390.       }
  3391.  
  3392.    if (this->memory != NULL)
  3393.       farmemfree(this->memory);
  3394.  
  3395.    if (this->save_pal[0] != NULL)
  3396.       farmemfree((BYTE far *)this->save_pal[0]);
  3397.  
  3398.    RGBEditor_Destroy(this->rgb[0]);
  3399.    RGBEditor_Destroy(this->rgb[1]);
  3400.    MoveBox_Destroy(this->movebox);
  3401.    delete(this);
  3402.    }
  3403.  
  3404.  
  3405. static void PalTable_Process(PalTable *this)
  3406.    {
  3407.    int ctr;
  3408.  
  3409.    getpalrange(0, colors, this->pal);
  3410.  
  3411.    /* Make sure all palette entries are 0-63 */
  3412.  
  3413.    for(ctr=0; ctr<768; ctr++)
  3414.       ((char *)this->pal)[ctr] &= 63;
  3415.  
  3416.    PalTable__UpdateDAC(this);
  3417.  
  3418.    RGBEditor_SetRGB(this->rgb[0], this->curr[0], &this->pal[this->curr[0]]);
  3419.    RGBEditor_SetRGB(this->rgb[1], this->curr[1], &this->pal[this->curr[0]]);
  3420.  
  3421.    if (!this->hidden)
  3422.       {
  3423.       MoveBox_SetPos(this->movebox, this->x, this->y);
  3424.       MoveBox_SetCSize(this->movebox, this->csize);
  3425.       if ( !MoveBox_Process(this->movebox) )
  3426.      {
  3427.      setpalrange(0, colors, this->pal);
  3428.      return ;
  3429.      }
  3430.  
  3431.       PalTable__SetPos(this, MoveBox_X(this->movebox), MoveBox_Y(this->movebox));
  3432.       PalTable__SetCSize(this, MoveBox_CSize(this->movebox));
  3433.  
  3434.       if ( MoveBox_ShouldHide(this->movebox) )
  3435.      {
  3436.      PalTable_SetHidden(this, TRUE);
  3437.      reserve_colors = FALSE;   /* <EAN> */
  3438.      }
  3439.       else
  3440.      {
  3441.      reserve_colors = TRUE;    /* <EAN> */
  3442.      PalTable__SaveRect(this);
  3443.      PalTable__Draw(this);
  3444.      }
  3445.       }
  3446.  
  3447.    PalTable__SetCurr(this, this->active,      PalTable__GetCursorColor(this));
  3448.    PalTable__SetCurr(this, (this->active==1)?0:1, PalTable__GetCursorColor(this));
  3449.    Cursor_Show();
  3450.  
  3451.    this->done = FALSE;
  3452.  
  3453.    while ( !this->done )
  3454.       RGBEditor_Edit(this->rgb[this->active]);
  3455.  
  3456.    Cursor_Hide();
  3457.    PalTable__RestoreRect(this);
  3458.    setpalrange(0, colors, this->pal);
  3459.    }
  3460.  
  3461.  
  3462. /*
  3463.  * interface to FRACTINT
  3464.  */
  3465.  
  3466.  
  3467.  
  3468. void EditPalette(void)         /* called by fractint */
  3469.    {
  3470.    int         oldlookatmouse = lookatmouse;
  3471.    int         oldsxoffs        = sxoffs;
  3472.    int         oldsyoffs        = syoffs;
  3473.    PalTable *pt;
  3474.  
  3475.    mem_init(strlocn, 10*1024);
  3476.  
  3477.    if ( (font8x8 = findfont(0)) == NULL )
  3478.       return ;
  3479.  
  3480.    plot = putcolor;
  3481.  
  3482.    line_buff = newx(max(sxdots,sydots));
  3483.  
  3484.    lookatmouse = 3;
  3485.    sxoffs = syoffs = 0;
  3486.  
  3487.    reserve_colors = TRUE;
  3488.    inverse = FALSE;
  3489.    fg_color = (BYTE)(255%colors);
  3490.    bg_color = (BYTE)(fg_color-1);
  3491.  
  3492.    Cursor_Construct();
  3493.    pt = PalTable_Construct();
  3494.    PalTable_Process(pt);
  3495.    PalTable_Destroy(pt);
  3496.    Cursor_Destroy();
  3497.  
  3498.    lookatmouse = oldlookatmouse;
  3499.    sxoffs = oldsxoffs;
  3500.    syoffs = oldsyoffs;
  3501.    delete(line_buff);
  3502.    }
  3503.  
  3504.