home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / sun / volume1 / palette / part01 / palette.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-18  |  37.5 KB  |  1,394 lines

  1. /* 
  2.  * palette.c - This file contains the program's main processing routines 
  3.  *             including all window creation, event handlers and 
  4.  *             the routines for manipulating colors and color maps.
  5.  *             
  6.  *             Exported routines:
  7.  *               main (duh)
  8.  *               MakeCMS
  9.  */
  10.  
  11. /**************************************************************************
  12.  *      palette - a colormap editor
  13.  *      Copyright (c) 1988 Wayne Mesard                                   *
  14.  *                                                                        *
  15.  *      This is free software.  It may be reproduced, retransmitted,      *
  16.  *      redistributed and otherwise propogated at will, provided that     *
  17.  *      no monetary profit is realized and that this notice remains       *
  18.  *      intact and in place.                                              *
  19.  *                                                                        *
  20.  *      Please direct bug reports, code enhancements and comments         *
  21.  *      to mesard@BBN.COM.                                                *
  22.  *                                                                        *
  23.  **************************************************************************/
  24.  
  25. #include <suntool/sunview.h>
  26. #include <suntool/panel.h>
  27. #include <suntool/canvas.h>
  28. #include <strings.h>
  29. #include <ctype.h>
  30. #include <stdio.h>
  31.  
  32. #include "patchlevel.h"
  33. #include "wsm_types.h"
  34. #include "hash.h"
  35.  
  36. #define MAX_COLORS 256
  37. #define MAX_BRIGHTNESS 255
  38.  
  39. #define MAX_COLORS_STR_LEN 9
  40.  
  41. #define PALETTE_H 160
  42. #define BUTT_SIZE 11
  43. #define NUM_MY_WINDOWS 4
  44.  
  45. enum updatecolor_msg {U_NEW_STATE, U_NEW_COLOR, U_NEW_CMS};
  46.  
  47.  
  48. static short mono_image[] = {
  49. #  include "mono.icon"
  50. };
  51. mpr_static(mono_pr, 64, 64, 1, mono_image);
  52. DEFINE_ICON_FROM_IMAGE(mono_icon, mono_image);
  53.  
  54. static short color_image[] = {
  55. #  include "color.icon"
  56. };
  57. mpr_static(color_pr, 64, 64, 8, color_image);
  58. static Icon color_icon;
  59.  
  60.  
  61. static short left_arrow_array[] = {
  62. #  include "left_arrow.pr"
  63. };
  64. mpr_static(left_arrow, 16, 16, 1, left_arrow_array);
  65.  
  66. static short right_arrow_array[] = {
  67. #  include "right_arrow.pr"
  68. };
  69. mpr_static(right_arrow, 16, 16, 1, right_arrow_array);
  70.  
  71.  
  72. static use_colormap = false;
  73. static boolean shallow_walkP = false;
  74. static Pixwin *my_pixies[NUM_MY_WINDOWS];
  75.  
  76. static Panel_item sliders[3];
  77. static Panel_item avg_markers[3];
  78. static Panel_item new_map_size;
  79. static Panel_item step_size_item;
  80. static Panel_item proportional_item;
  81. static Panel_item reset_on_reread;
  82. static Panel_item file_type;
  83. static Panel_item file_name;
  84.  
  85. static int cur_entry = 0;
  86. static int cur_range_end = 0;
  87. static int cur_size;
  88. static char *cur_name;
  89. static Panel_item cur_cms_item;
  90. static struct cms_map cur_map;
  91.  
  92. static unsigned char clipboard_red[MAX_COLORS];
  93. static unsigned char clipboard_green[MAX_COLORS];
  94. static unsigned char clipboard_blue[MAX_COLORS];
  95. static struct cms_map clipboard = 
  96.           {clipboard_red, clipboard_green, clipboard_blue};
  97. static short clipboard_entries = 0;
  98.  
  99. static Frame frame;
  100. static int my_frame_fd;
  101. static Panel control_panel, table_panel;
  102. static Panel_item cur_color_item;
  103. static Panel_item msg_item;
  104. static char frame_cms_name[CMS_NAMESIZE];
  105. static char subwins_cms_name[CMS_NAMESIZE];
  106.  
  107.  
  108. main(argc, argv)
  109. int argc;
  110. char **argv;
  111. {
  112.     extern int Get_Root();
  113.     void InitWindow(), Message();
  114.     void SelectCMS();
  115.     boolean WalkWinTree();
  116.     int rootfd, i;
  117.  
  118.     for (i = argc; i>1;)
  119.     if (argv[--i][0] == '-')
  120.         if (argv[i][1] == 'f')
  121.         shallow_walkP = true;
  122.         else if (argv[i][1] == 's')
  123.         use_colormap = true;
  124.          /* else This must be an arg for the frame. */
  125.  
  126.     H_MakeNull();
  127.     InitWindow(argc, argv);
  128.  
  129.     if ((rootfd=Get_Root(frame))==-1) {
  130.     fprintf(stderr, "%s: Error opening screen's root window\n", argv[0]);
  131.     exit(1);
  132.     /*NOTREACHED*/
  133.     }
  134.  
  135.     if (!WalkWinTree(rootfd, shallow_walkP))
  136.     Message("<Error: CMS table full.  Not all windows processed.>", 0);
  137.     (void) close(rootfd);
  138.     (void) WalkWinTree(my_frame_fd, true); /* Since it's not in the tree yet. */
  139.     cur_name = NULL;
  140.     SelectCMS(frame_cms_name);
  141.     window_main_loop(frame);
  142. }
  143.  
  144.  
  145.  
  146. /* 
  147.  * InitWindow - Set up all the windows and panel items.
  148.  */
  149.  
  150. static void InitWindow(argc, argv)
  151. int argc;
  152. char **argv;
  153. {
  154.     extern Pixwin *MakePalette();
  155.     void slider_notify();
  156.     void ArrowEvent();
  157.     void Copy(), Paste();
  158.     Panel_setting KeyedEntry(), NumericText();
  159.     void ClickOnCMS();
  160.     void KeyEvent();
  161.     void UseColorMap(), WalkDepth();
  162.     void ResizeCanvas(), CanvasEvent();
  163.     void CreateNewMap(), Reread_Maps(), Save(), Load(), Quit();
  164.  
  165.     static char RGBName[][6] = {"Red  ", "Green", "Blue "};
  166.     Canvas canvas;
  167.     char buf[16];
  168.     int i, row = -1;
  169.     unsigned char **ptr;
  170.  
  171.  
  172.     color_icon = icon_create(ICON_IMAGE, &color_pr, 0);
  173.  
  174.     frame = window_create(NULL, FRAME,
  175.               FRAME_NO_CONFIRM, TRUE,
  176.               FRAME_ICON, &mono_icon,
  177.               FRAME_LABEL, "Palette",
  178.               FRAME_ARGS, argc, argv,
  179.               WIN_CONSUME_KBD_EVENT, WIN_NO_EVENTS,
  180.               0);
  181.  
  182.     control_panel = window_create(frame, PANEL, 
  183.                 PANEL_ITEM_X_GAP, 5,
  184.                 WIN_EVENT_PROC, KeyEvent,
  185.                 0);
  186.  
  187.     for (i= -1; ++i<3;) {
  188.     (void) sprintf(buf, "%s:", RGBName[i]);
  189.     switch (i) {
  190.       case 0:
  191.         ptr = &(cur_map.cm_red);
  192.         break;
  193.       case 1:
  194.         ptr = &(cur_map.cm_green);
  195.         break;
  196.       case 2:
  197.         ptr = &(cur_map.cm_blue);
  198.         break;
  199.     }
  200.  
  201.     sliders[i] = panel_create_item(control_panel, PANEL_SLIDER,
  202.               PANEL_ITEM_X, ATTR_COL(0),
  203.               PANEL_ITEM_Y, ATTR_ROW(++row),
  204.               PANEL_LABEL_STRING, buf,
  205.               PANEL_CLIENT_DATA, ptr,
  206.               PANEL_MIN_VALUE, 0,
  207.               PANEL_MAX_VALUE, MAX_COLORS-1,
  208.               PANEL_SHOW_RANGE, FALSE,
  209.               PANEL_SLIDER_WIDTH, MAX_COLORS,
  210.               PANEL_NOTIFY_PROC, slider_notify,
  211.               PANEL_NOTIFY_LEVEL, PANEL_ALL,
  212.               0);
  213.  
  214.     avg_markers[i] = panel_create_item(control_panel, PANEL_MESSAGE,
  215.               PANEL_LABEL_STRING, "*",
  216.               PANEL_LABEL_BOLD, TRUE,
  217.               0);
  218.  
  219.     (void) panel_create_item(control_panel, PANEL_BUTTON,
  220.               PANEL_LABEL_IMAGE, &left_arrow,
  221.               PANEL_NOTIFY_PROC, ArrowEvent,
  222.               PANEL_CLIENT_DATA, sliders[i],
  223.               0);
  224.  
  225.     (void) panel_create_item(control_panel, PANEL_BUTTON,
  226.               PANEL_LABEL_IMAGE, &right_arrow,
  227.               PANEL_NOTIFY_PROC, ArrowEvent,
  228.               PANEL_CLIENT_DATA, sliders[i],
  229.               0);
  230.  
  231.     
  232.     }
  233.     panel_set(control_panel, PANEL_ITEM_X_GAP, 15, 0);
  234.  
  235.     cur_color_item =  panel_create_item(control_panel, PANEL_TEXT,
  236.                  PANEL_ITEM_X, ATTR_COL(0),
  237.                  PANEL_ITEM_Y, ATTR_ROW(++row),
  238.                  PANEL_LABEL_BOLD, TRUE,
  239.                  PANEL_LABEL_STRING, "Current Color:",
  240.                  PANEL_VALUE_STORED_LENGTH,  MAX_COLORS_STR_LEN,
  241.                  PANEL_VALUE_DISPLAY_LENGTH, MAX_COLORS_STR_LEN,
  242.                  PANEL_NOTIFY_LEVEL, PANEL_ALL,
  243.                  PANEL_NOTIFY_PROC, KeyedEntry,
  244.                  0);
  245.  
  246.     (void) panel_create_item(control_panel, PANEL_BUTTON,
  247.                  PANEL_NOTIFY_PROC, Copy,
  248.                  PANEL_LABEL_IMAGE,
  249.                    panel_button_image(control_panel,
  250.                           "Copy", BUTT_SIZE, 0),
  251.                  0);
  252.  
  253.     (void) panel_create_item(control_panel, PANEL_BUTTON,
  254.                  PANEL_NOTIFY_PROC, Paste,
  255.                  PANEL_LABEL_IMAGE,
  256.                    panel_button_image(control_panel,
  257.                           "Paste", BUTT_SIZE, 0),
  258.                  0);
  259.  
  260.     msg_item = panel_create_item(control_panel, PANEL_MESSAGE, 
  261.                  PANEL_ITEM_X, ATTR_COL(0),
  262.                  PANEL_ITEM_Y, ATTR_ROW(++row),
  263.                  PANEL_LABEL_STRING, " ",
  264.                  0);
  265.                    
  266.     (void) panel_create_item(control_panel, PANEL_BUTTON,
  267.                  PANEL_ITEM_X, ATTR_COL(0),
  268.                  PANEL_ITEM_Y, ATTR_ROW(++row),
  269.                  PANEL_NOTIFY_PROC, CreateNewMap,
  270.                  PANEL_LABEL_IMAGE,
  271.                    panel_button_image(control_panel,
  272.                           "New Map", BUTT_SIZE, 0),
  273.                  0);
  274.  
  275.     new_map_size = panel_create_item(control_panel, PANEL_CYCLE,
  276.                  PANEL_ITEM_X, ATTR_COL(15),
  277.                  PANEL_ITEM_Y, ATTR_ROW(row),
  278.                  PANEL_LABEL_BOLD, TRUE,
  279.                  PANEL_LABEL_STRING, "New Map Size:",
  280.                  PANEL_CHOICE_STRINGS, 
  281.                    "  2","  4","  8"," 16"," 32",
  282.                    " 64","128","256", 0,
  283.                  PANEL_VALUE, 7,
  284.                  0);
  285.  
  286.     proportional_item =  panel_create_item(control_panel, PANEL_CYCLE,
  287.                  PANEL_ITEM_X, ATTR_COL(15),
  288.                  PANEL_ITEM_Y, ATTR_ROW(++row),
  289.                  PANEL_LABEL_STRING, "Uniform Steps:",
  290.                  PANEL_LABEL_BOLD, TRUE,
  291.                  PANEL_CHOICE_STRINGS, "Yes", "No", 0,
  292.                  PANEL_VALUE, 0,
  293.                  0);
  294.  
  295.     /* A bug in SunOS 3.4 causes the following item to be 2 pixels above
  296.      * the row using screen.r.14.  I have no idea why.  Other fonts don't
  297.      * seem to be effected, and other sizes of screen are shifted by 
  298.      * different distances.  Anyway, the "+2" below should be adjusted or
  299.      * removed as your system configuration dictates.
  300.      */
  301.     step_size_item = panel_create_item(control_panel, PANEL_TEXT,
  302.                  PANEL_LABEL_BOLD, TRUE,
  303.                  PANEL_LABEL_STRING, "Step Size:",
  304.                  PANEL_ITEM_Y, ATTR_ROW(row)+2,
  305.                  PANEL_VALUE_STORED_LENGTH,  3,
  306.                  PANEL_VALUE_DISPLAY_LENGTH, 3,
  307.                  PANEL_VALUE, "10",
  308.                  PANEL_NOTIFY_LEVEL, PANEL_ALL,
  309.                  PANEL_NOTIFY_PROC, NumericText,
  310.                  0);
  311.  
  312.     (void) panel_create_item(control_panel, PANEL_BUTTON,
  313.                  PANEL_ITEM_X, ATTR_COL(0),
  314.                  PANEL_ITEM_Y, ATTR_ROW(++row),
  315.                  PANEL_NOTIFY_PROC, Reread_Maps,
  316.                  PANEL_LABEL_IMAGE,
  317.                    panel_button_image(control_panel,
  318.                           "Reread Maps", BUTT_SIZE, 0),
  319.                  0);
  320.                  
  321.     (void) panel_create_item(control_panel, PANEL_CYCLE,
  322.                  PANEL_ITEM_X, ATTR_COL(15),
  323.                  PANEL_ITEM_Y, ATTR_ROW(row),
  324.                  PANEL_NOTIFY_PROC, WalkDepth,
  325.                  PANEL_LABEL_BOLD, TRUE,
  326.                  PANEL_LABEL_STRING, "Read From:",
  327.                  PANEL_CHOICE_STRINGS, 
  328.                    "All windows", "Top level frames", 0,
  329.                  PANEL_VALUE, shallow_walkP,
  330.                  0);
  331.  
  332.     reset_on_reread = panel_create_item(control_panel, PANEL_CYCLE,
  333.                  PANEL_ITEM_X, ATTR_COL(15),
  334.                  PANEL_ITEM_Y, ATTR_ROW(++row),
  335.                  PANEL_LABEL_BOLD, TRUE,
  336.                  PANEL_LABEL_STRING, "On Reread:",
  337.                  PANEL_CHOICE_STRINGS, 
  338.                    "Reset table first", "Don't reset table", 0,
  339.                  0);
  340.  
  341.     (void) panel_create_item(control_panel, PANEL_BUTTON,
  342.                  PANEL_ITEM_X, ATTR_COL(0),
  343.                  PANEL_ITEM_Y, ATTR_ROW(++row),
  344.                  PANEL_NOTIFY_PROC, Save,
  345.                  PANEL_LABEL_IMAGE,
  346.                    panel_button_image(control_panel,
  347.                           "Save", BUTT_SIZE, 0),
  348.                  0);
  349.  
  350.     file_type = panel_create_item(control_panel, PANEL_CYCLE,
  351.                  PANEL_ITEM_X, ATTR_COL(15),
  352.                  PANEL_LABEL_BOLD, TRUE,
  353.                  PANEL_LABEL_STRING, "Save Type:",
  354.                  PANEL_CHOICE_STRINGS,
  355.                    "RGB arrays", "RGB list", "Clear raster file",
  356.                    "Palette raster file", 0,
  357.                  0);
  358.  
  359.  
  360.     (void) panel_create_item(control_panel, PANEL_BUTTON,
  361.                  PANEL_ITEM_X, ATTR_COL(0),
  362.                  PANEL_ITEM_Y, ATTR_ROW(++row),
  363.                  PANEL_NOTIFY_PROC, Load,
  364.                  PANEL_LABEL_IMAGE,
  365.                    panel_button_image(control_panel,
  366.                           "Load", BUTT_SIZE, 0),
  367.                  0);
  368.  
  369.  
  370.     file_name = panel_create_item(control_panel, PANEL_TEXT,
  371.                  PANEL_ITEM_X, ATTR_COL(15),
  372.                  PANEL_ITEM_Y, ATTR_ROW(row),
  373.                  PANEL_LABEL_BOLD, TRUE,
  374.                  PANEL_LABEL_STRING, "File Name:",
  375.                  PANEL_VALUE_STORED_LENGTH,  128,
  376.                  PANEL_VALUE_DISPLAY_LENGTH, 24,
  377.                  PANEL_VALUE, "palette.rgb",
  378.                  0);
  379.  
  380.     (void) panel_create_item(control_panel, PANEL_BUTTON,
  381.                  PANEL_ITEM_X, ATTR_COL(0),
  382.                  PANEL_ITEM_Y, ATTR_ROW(++row),
  383.                  PANEL_NOTIFY_PROC, Quit,
  384.                  PANEL_LABEL_IMAGE,
  385.                    panel_button_image(control_panel,
  386.                           "Quit", BUTT_SIZE, 0),
  387.                  0);
  388.  
  389.     (void) panel_create_item(control_panel, PANEL_CYCLE,
  390.                  PANEL_ITEM_X, ATTR_COL(15),
  391.                  PANEL_NOTIFY_PROC, UseColorMap,
  392.                  PANEL_LABEL_BOLD, TRUE,
  393.                  PANEL_LABEL_STRING, "Palette's Colormap:",
  394.                  PANEL_CHOICE_STRINGS, "Its own", "Selected", 0,
  395.                  PANEL_VALUE, use_colormap,
  396.                  0);
  397.  
  398.     window_fit(control_panel);
  399.     window_fit_width(frame);
  400.     table_panel = window_create(frame, PANEL, 
  401.                 PANEL_ITEM_X_GAP, 60,
  402.                 PANEL_EVENT_PROC, ClickOnCMS,
  403.                 WIN_VERTICAL_SCROLLBAR, scrollbar_create(0),
  404.                 WIN_ROWS, 3,
  405.                 WIN_IGNORE_KBD_EVENT, WIN_ASCII_EVENTS,
  406.                 WIN_CONSUME_PICK_EVENT, MS_LEFT,
  407.                 WIN_INPUT_DESIGNEE, 
  408.                       i = (int) window_get(control_panel,
  409.                                WIN_DEVICE_NUMBER),
  410.                 0);
  411.  
  412.     canvas = window_create(frame, CANVAS, 
  413.                    CANVAS_RESIZE_PROC, ResizeCanvas,
  414.                    CANVAS_FIXED_IMAGE, FALSE,
  415.                    CANVAS_AUTO_CLEAR, FALSE,
  416.                    WIN_CONSUME_PICK_EVENTS,
  417.                      WIN_UP_EVENTS, LOC_DRAG,
  418.                      MS_LEFT, MS_MIDDLE, 0,
  419.                    WIN_INPUT_DESIGNEE, i,
  420.                    WIN_EVENT_PROC, CanvasEvent,
  421.                    WIN_BELOW, table_panel,
  422.                    WIN_HEIGHT, PALETTE_H,
  423.                    0);
  424.  
  425.     my_pixies[0] = MakePalette(canvas);
  426.     my_pixies[1] = (Pixwin *) window_get(frame, WIN_PIXWIN);
  427.     my_pixies[2] = (Pixwin *) window_get(control_panel, WIN_PIXWIN);
  428.     my_pixies[3] = (Pixwin *) window_get(table_panel, WIN_PIXWIN);
  429.  
  430.     pw_getcmsname(my_pixies[1], frame_cms_name);
  431.     pw_getcmsname(my_pixies[2], subwins_cms_name);
  432.  
  433.     my_frame_fd = (int) window_get(frame, WIN_FD);
  434.     window_fit_height(frame);
  435. }
  436.  
  437.  
  438.  
  439. /* 
  440.  * Message - Put a string in the message line (with an optional numeric 
  441.  *           argument.
  442.  */
  443.  
  444. static void Message(s, i)
  445. char *s;
  446. int i;
  447. {
  448.     char buf[80];
  449.     
  450.     (void) sprintf(buf, s, i);
  451.     panel_set(msg_item, PANEL_LABEL_STRING, buf, 0);
  452. }
  453.  
  454.  
  455.  
  456. /* 
  457.  * SelectEntry - Do the work when the user selects a new color or range 
  458.  *               of colors.  index need not be less than range_end.  The 
  459.  *               sliders and the Current Color indicator are updated.  
  460.  *               And the current color(s) are highlighted in the palette.
  461.  *               (Single colors are not highlighted if the colormap is of 
  462.  *               size 2.)  
  463.  *              
  464.  *               If index or range_end are illegal values, the routine 
  465.  *               silently exits.
  466.  */
  467.  
  468. static void SelectEntry(index, range_end)
  469. int index, range_end;
  470. {
  471.     extern void HighlightSwatch(), BoxSwatches(), DrawPalette();
  472.     unsigned char **ptr;
  473.     char buf[MAX_COLORS_STR_LEN+1];
  474.     int i, j, val, prev;
  475.     boolean avgP, avg_existsP = false;
  476.  
  477.     if (index > range_end) {
  478.     if (range_end == -1)
  479.         range_end = index;
  480.     else {
  481.         i = index;
  482.         index = range_end;
  483.         range_end = i;
  484.     }
  485.     }
  486.     if (index < 0 || range_end >= cur_size)
  487.     return;
  488.     cur_entry = index;
  489.     cur_range_end = range_end;
  490.     
  491.     DrawPalette(cur_size);
  492.  
  493.     if (cur_entry == cur_range_end) {
  494.     (void) sprintf(buf, "%d", cur_entry);
  495.     if (cur_size > 2)
  496.         HighlightSwatch(cur_entry, cur_size-1);
  497.     }
  498.     else {
  499.     BoxSwatches(cur_entry, cur_range_end);
  500.     (void) sprintf(buf, "%d..%d", cur_entry, cur_range_end);
  501.     }
  502.     panel_set_value(cur_color_item, buf);
  503.  
  504.     for (i= -1; ++i<3;) {
  505.     avgP = FALSE;
  506.     ptr = (unsigned char **) panel_get(sliders[i], PANEL_CLIENT_DATA);
  507.     for (val = 0, j = cur_entry, prev = ((*ptr)[cur_entry]);
  508.          j <= cur_range_end; j++) {
  509.         avgP = (avgP | (prev != ((*ptr)[j])));
  510.         val += (prev = (*ptr)[j]);
  511.     }
  512.     panel_set(sliders[i], PANEL_VALUE, val/(cur_range_end-cur_entry+1), 0);
  513.     panel_set(avg_markers[i], PANEL_SHOW_ITEM, avgP, 0);
  514.     avg_existsP = (avg_existsP | avgP);
  515.     }
  516.     Message((avg_existsP ? "* Starred items represent averages." : ""), 0);
  517. }
  518.  
  519.  
  520.  
  521. /* 
  522.  * slider_notify - When the user clicks on a slider, update the colormap,
  523.  *                 the colormap array, and hide the slider's asterisk 
  524.  *                 item (in case it's on).
  525.  */
  526.     
  527. static void slider_notify(slider, value, event)
  528. Panel_item slider;
  529. int value;
  530. Event *event;
  531. {
  532.     void UpdateColorMaps();
  533.     unsigned char **ptr;
  534.     int i;
  535.  
  536.     ptr = (unsigned char **) panel_get(slider, PANEL_CLIENT_DATA);
  537.     for (i=cur_entry; i <= cur_range_end; ++i)
  538.     (*ptr)[i] = (unsigned char) value;
  539.  
  540.     UpdateColorMaps(U_NEW_COLOR);
  541.     panel_set((Panel_item)panel_get(slider, PANEL_NEXT_ITEM),
  542.           PANEL_SHOW_ITEM, FALSE, 0);
  543. }
  544.  
  545.  
  546. /* 
  547.  * ArrowEvent - When the user clicks on an arrow, update its slider, 
  548.  *              increment the current color(s) (possibly by a linearly 
  549.  *              increasing amount), update the array and the colormap, 
  550.  *              and possibly turn off the color's asterisk (if all the 
  551.  *              colors in the range have become equal).
  552.  */
  553.  
  554. static void ArrowEvent(button, event)
  555. Panel_item button;
  556. Event *event;
  557. {
  558.     extern int atoi();
  559.     int i, prev, new_val, total = 0;
  560.     boolean avgP = FALSE;
  561.     boolean proportional = (boolean) panel_get_value(proportional_item);
  562.     int step_size = atoi(panel_get_value(step_size_item));
  563.     Panel_item my_slider = panel_get(button, PANEL_CLIENT_DATA);
  564.     unsigned char **ptr;
  565.  
  566.     if ((Pixrect *)panel_get(button, PANEL_LABEL_IMAGE) == &left_arrow)
  567.     step_size = -step_size;
  568.  
  569.     ptr = (unsigned char **) panel_get(my_slider, PANEL_CLIENT_DATA);
  570.     for (i = cur_entry, prev = -1; i <= cur_range_end; i++) {
  571.     new_val = (*ptr)[i] + (step_size * (proportional ? i-cur_entry+1 : 1));
  572.     if (new_val > MAX_BRIGHTNESS)
  573.         new_val = MAX_BRIGHTNESS;
  574.     else if (new_val < 0)
  575.         new_val = 0;
  576.     avgP = (avgP | (prev == -1 ? FALSE : (prev != new_val)));
  577.     total += ((*ptr)[i] = prev = new_val);
  578.     }
  579.     UpdateColorMaps(U_NEW_COLOR);
  580.     panel_set(my_slider, PANEL_VALUE, total/(cur_range_end-cur_entry+1), 0);
  581.     panel_set((Panel_item)panel_get(my_slider, PANEL_NEXT_ITEM),
  582.           PANEL_SHOW_ITEM, avgP, 0);
  583. }
  584.  
  585.  
  586.  
  587. /* 
  588.  * Copy - Copy the current range onto the clipboard.
  589.  */
  590.  
  591. static void Copy()
  592. {
  593.     void UpdateColorMaps();
  594.     int nbytes;
  595.  
  596.     clipboard_entries = 1+(cur_range_end-cur_entry);
  597.     nbytes = sizeof(unsigned char)*clipboard_entries;
  598.     bcopy((char *) cur_map.cm_red + cur_entry, 
  599.       (char *) clipboard.cm_red, nbytes);
  600.     bcopy((char *) cur_map.cm_green + cur_entry, 
  601.       (char *) clipboard.cm_green, nbytes);
  602.     bcopy((char *) cur_map.cm_blue + cur_entry, 
  603.       (char *) clipboard.cm_blue, nbytes);
  604. }
  605.  
  606.  
  607. /* 
  608.  * Paste - Paste the clipboard contents onto the current CMS starting at 
  609.  *         the current entry.
  610.  */
  611.  
  612. static void Paste()
  613. {
  614.     void UpdateColorMaps();
  615.  
  616.     int nbytes = sizeof(unsigned char) *
  617.     (clipboard_entries + cur_entry > cur_size ? 
  618.      cur_size - cur_entry : clipboard_entries);
  619.                     
  620.     bcopy((char *) clipboard.cm_red, (char *) cur_map.cm_red + cur_entry, 
  621.       nbytes);
  622.     bcopy((char *) clipboard.cm_green, (char *) cur_map.cm_green + cur_entry, 
  623.       nbytes);
  624.     bcopy((char *) clipboard.cm_blue, (char *) cur_map.cm_blue + cur_entry, 
  625.       nbytes);
  626.     UpdateColorMaps(U_NEW_COLOR);
  627.     SelectEntry(cur_entry, cur_range_end);
  628.     if (clipboard_entries > (nbytes / sizeof(unsigned char)))
  629.     Message("<Only the first %d clipboard items fit.>", 
  630.         (nbytes / sizeof(unsigned char)));
  631. }
  632.  
  633.  
  634.  
  635. /* 
  636.  * KeyEvent - Take the appropriate action when the user types a key.  
  637.  *            Note that ascii input from all three windows are directed 
  638.  *            to the control_panel.
  639.  *               All that crap with esp_seq is necessary because you 
  640.  *            can't get KEY_RIGHT() events for the arrow keys.  (At 
  641.  *            least not on my Sun3/160.)  So this routine looks for a 
  642.  *            consecutive <Esc>[n, where "n" is D or C.
  643.  */
  644.  
  645. static void KeyEvent(win, event, arg)
  646. Window win;
  647. Event *event;
  648. caddr_t arg;
  649. {
  650.     void SelectEntry();
  651.     void Quit();
  652.  
  653.     static short esq_seq = 0;
  654.  
  655.     if (esq_seq == 2)
  656.     switch (event_id(event)) {
  657.       case 'D':
  658.         event_set_id(event, '<');
  659.         break;
  660.       case 'C':
  661.         event_set_id(event, '>');
  662.         break;
  663.     }
  664.     
  665.     switch(event_id(event)) {
  666.       case '\033':
  667.     esq_seq = 1;
  668.     break;
  669.       case '[':
  670.     if (esq_seq == 1)
  671.         esq_seq = 2;
  672.     break;
  673.       case '<':
  674.     SelectEntry(cur_entry-1, -1);
  675.     esq_seq = 0;
  676.     break;
  677.       case '>':
  678.     SelectEntry(cur_entry+1, -1);
  679.     esq_seq = 0;
  680.     break;
  681.       case '\003':
  682.     Quit();
  683.       default:
  684.     esq_seq = 0;
  685.     window_default_event_proc(win, event, arg);
  686.     break;
  687.     
  688.     }
  689. }
  690.  
  691.  
  692. /* 
  693.  * KeyedEntry - Preprocess keyboard input to the Current Color item.  
  694.  *              Only allow digits and periods to be entered.  When 
  695.  *              Return is pressed, parse the text for the starting and 
  696.  *              ending values of the new range.  If no starting or ending
  697.  *              range is found, assume zero and the highest value in the 
  698.  *              current colormap, respectively.
  699.  */
  700.  
  701. static Panel_setting 
  702. KeyedEntry(item, event)
  703. Panel_item item;
  704. Event *event;
  705. {
  706.     extern int atoi();
  707.     void SelectEntry();
  708.     int t1, t2;
  709.     boolean error_flag = false;
  710.     char *s, *ptr;
  711.  
  712.     if (event_id(event)=='\r' || event_id(event)=='\n') {
  713.     if (ptr = rindex(s = panel_get_value(item), '.')) {
  714.         if (*++ptr == '\0')
  715.         t1 = cur_size-1;
  716.         else
  717.         t1 = atoi(ptr);
  718.         if (t1 >= cur_size || (t2 = atoi(s)) > cur_size)
  719.         error_flag = true;
  720.         else
  721.         SelectEntry(t2, t1);
  722.     }
  723.     else if ((t1 = atoi(panel_get_value(item))) < cur_size)
  724.         SelectEntry(atoi(panel_get_value(item)), -1);
  725.     else
  726.         error_flag = true;
  727.  
  728.     if (error_flag)
  729.         Message("<Valid colors for this cms are 0..%d>", cur_size-1);
  730.     }
  731.     else if (iscntrl(event_id(event)) || isdigit(event_id(event)) ||
  732.          event_id(event) == '.')
  733.     return(panel_text_notify(item, event));
  734.  
  735.     return(PANEL_NONE);
  736. }
  737.  
  738.  
  739. /* 
  740.  * NumericText - Notify procedure for a text item that only wants 
  741.  *               digits in itself.
  742.  */
  743.  
  744. static Panel_setting 
  745. NumericText(item, event)
  746. Panel_item item;
  747. Event *event;
  748. {
  749.     return ((isdigit(event_id(event)) || iscntrl(event_id(event))) ?
  750.         panel_text_notify(item, event) : PANEL_NONE);
  751. }
  752.  
  753.  
  754.     
  755.  
  756. /*
  757.  *  UpdateColorMaps - Sets the colormap of the four local windows 
  758.  *                    acccording to the value of use_colormap.  The 
  759.  *                    amount of action required is determined by the 
  760.  *                    type parameter and the current state of the 
  761.  *                    use_colormap variable.
  762.  *       
  763.  *            U_NEW_COLOR - simply updates the window manager's record 
  764.  *                          of the current CMS to match Palette's.
  765.  *            U_NEW_CMS -   tells the window manager to assign a new 
  766.  *                          colormap to Palette's canvas window, or to 
  767.  *                          all its windows if use_colormap is true.
  768.  *            U_NEW_STATE - Sets the colormaps of the other (non-canvas) 
  769.  *                          windows when the "Palette's Colormap" feature
  770.  *                          gets toggled.  Forces the wm to redraw the
  771.  *                          windows too.
  772.  */
  773.  
  774. static void UpdateColorMaps(type)
  775. enum updatecolor_msg type;
  776. {
  777.     int i, win_limit;
  778.     char *name;
  779.  
  780.     name = cur_name;
  781.     win_limit = ((type == U_NEW_STATE || use_colormap) ? NUM_MY_WINDOWS : 1);
  782.     for (i = (type==U_NEW_STATE? 0 : -1); ++i < win_limit;) {
  783.     if (i == 1 && !use_colormap)
  784.         name = frame_cms_name;
  785.     if (i == 2 && !use_colormap)
  786.         name = subwins_cms_name;
  787.  
  788.     if (type != U_NEW_COLOR)
  789.         pw_setcmsname(my_pixies[i], name);
  790.  
  791.     if (i==0 || use_colormap)
  792.         pw_putcolormap(my_pixies[i], 0, cur_size, 
  793.                cur_map.cm_red, cur_map.cm_green, cur_map.cm_blue);
  794.     }
  795.     if (type == U_NEW_STATE || (type == U_NEW_CMS && use_colormap)) {
  796.     wmgr_refreshwindow(my_frame_fd);
  797.     if (cur_size > 4 && cur_size < MAX_COLORS && use_colormap)
  798.         window_set(frame, FRAME_ICON, color_icon, 0);
  799.     else
  800.         window_set(frame, FRAME_ICON, &mono_icon, 0);
  801.     }
  802. }
  803.  
  804.  
  805. /* 
  806.  * UseColorMap - Change state of the Palette's Colormap feature, and 
  807.  *               update the windows as appropriate.
  808.  *               
  809.  *               See BorrowFramesCMS for explanation of the conditional 
  810.  *               statments.
  811.  */
  812.  
  813. static void UseColorMap(item, value, event)
  814. Panel_item item;
  815. int value;
  816. Event *event;
  817. {
  818.     void UpdateColorMaps(), BorrowFramesCMS(), SelectCMS();
  819.     char *glob_name = cur_name;
  820.     
  821.     if (value == false)
  822.     BorrowFramesCMS();
  823.  
  824.     use_colormap = value;
  825.     UpdateColorMaps(U_NEW_STATE);
  826.  
  827.     if (value == false)
  828.     SelectCMS(glob_name);
  829. }
  830.  
  831.  
  832.  
  833. /* 
  834.  * WalkDepth
  835.  */
  836.  
  837. static void WalkDepth(item, value, event)
  838. Panel_item item;
  839. int value;
  840. Event *event;
  841. {
  842.     shallow_walkP = (boolean) value;
  843. }
  844.  
  845.  
  846.  
  847. /* 
  848.  * CreateNewMap - Enter a new map in the colormap table.
  849.  */
  850.  
  851. static void CreateNewMap()
  852. {
  853.     extern char *malloc();
  854.     extern int getpid();
  855.     boolean MakeCMS();
  856.     static int gensym = 0;
  857.     static struct colormapseg data; /* static so cur_name can point to it. */
  858.     int i;
  859.  
  860.     (void) sprintf(data.cms_name, "Palette%d-%d", getpid(), ++gensym);
  861.     data.cms_size = 1<<((int)panel_get_value(new_map_size)+1);
  862.  
  863.     cur_map.cm_red = (unsigned char *) malloc((unsigned) data.cms_size);
  864.     cur_map.cm_green = (unsigned char *) malloc((unsigned) data.cms_size);
  865.     cur_map.cm_blue = (unsigned char *) malloc((unsigned) data.cms_size);
  866.     for (i = -1; ++i < data.cms_size;)
  867.     cur_map.cm_red[i] = cur_map.cm_green[i] = cur_map.cm_blue[i] =
  868.         i*(255/(data.cms_size-1.0));
  869.  
  870.     if (MakeCMS(&data, &cur_map)) {
  871.     panel_paint(table_panel, PANEL_NO_CLEAR);
  872.     SelectCMS(data.cms_name);
  873.     }
  874.     else
  875.     Message("<Error: CMS table full.  Try \"Reread Maps\".>", 0);
  876. }
  877.  
  878.  
  879.     
  880.  
  881. /* 
  882.  * Save - Save the current colormap in the specified file, in one of the
  883.  *        three specified formats.
  884.  */
  885.  
  886. static void Save()
  887. {
  888.     FILE *fp;
  889.     int i;
  890.     char *name;
  891.     char buf[180];
  892.     boolean error = false;
  893.     /* RGB array */
  894.     int c;
  895.     unsigned char **ptr;
  896.  
  897.     /* Rasterfile */
  898.     extern int SavePalette();
  899.     colormap_t colormap;
  900.     Pixrect *null_pr;
  901.  
  902.     if (fp = fopen(name = panel_get_value(file_name), "r")) {
  903.     (void) fclose(fp);
  904.     (void) sprintf(buf, "The file \"%s\" exists.  Press the left mouse\
  905.  button to overwrite.  To cancel press the right mouse button.", name);
  906.     if (wmgr_confirm(my_frame_fd, buf) == 0) {
  907.         Message("Save operation cancelled.", 0);
  908.         return;
  909.     }
  910.     }
  911.     fp = fopen(panel_get_value(file_name), "w");
  912.     if (fp==NULL) {
  913.     error = true;
  914.     Message("<Error: Couldn't open specified file.>", 0);
  915.     }
  916.     else {
  917.     switch((int)panel_get_value(file_type)) {
  918.       case 0:        /* RGB arrays */
  919.         for (i = -1; ++i<3;) {
  920.         switch (i) {
  921.           case 0:
  922.             name = "red";
  923.             ptr = &(cur_map.cm_red);
  924.             break;
  925.           case 1:
  926.             name = "green";
  927.             ptr = &(cur_map.cm_green);
  928.             break;
  929.           case 2:
  930.             name = "blue";
  931.             ptr = &(cur_map.cm_blue);
  932.             break;
  933.         }
  934.  
  935.         (void) fprintf(fp, "unsigned char %s[%d] = %*c", name, cur_size,
  936.             (2*(i==0)+(i==2)+(cur_size>11)+(cur_size<100)), '{');
  937.         for(c = -1; ++c < cur_size;) {
  938.             if ((c%16) == 11)
  939.             (void) fprintf(fp, "\n/*%3d*/ ", c );
  940.             (void) fprintf(fp, "%3d%c", (*ptr)[c], 
  941.                 (c==cur_size-1 ? '}' : ','));
  942.         }
  943.         (void) fprintf(fp, ";\n\n");
  944.         }
  945.         break;
  946.       case 1:        /* Number list */
  947.         for (i = -1; ++i < cur_size; )
  948.         (void) fprintf(fp, "%3d %3d %3d\n", *(cur_map.cm_red+i), 
  949.                    *(cur_map.cm_green+i), *(cur_map.cm_blue+i));
  950.         break;
  951.       case 2:        /* Null rasterfile w/ colormap */
  952.         colormap.type = RMT_EQUAL_RGB;
  953.         colormap.length = cur_size;
  954.         colormap.map[0] = cur_map.cm_red;
  955.         colormap.map[1] = cur_map.cm_green;
  956.         colormap.map[2] = cur_map.cm_blue;
  957.  
  958.         null_pr = mem_create(0, 0, 8);
  959.  
  960.         if (pr_dump(null_pr, fp, &colormap, RT_STANDARD, 0))
  961.         error = true;
  962.         pr_destroy(null_pr);
  963.         break;
  964.       case 3:        /* Picture of the palette */
  965.         colormap.type = RMT_EQUAL_RGB;
  966.         colormap.length = cur_size;
  967.         colormap.map[0] = cur_map.cm_red;
  968.         colormap.map[1] = cur_map.cm_green;
  969.         colormap.map[2] = cur_map.cm_blue;
  970.  
  971.         DrawPalette(cur_size);
  972.  
  973.         if (SavePalette(fp, &colormap))
  974.         error = true;
  975.  
  976.         HighlightSwatch(cur_entry, cur_size-1);
  977.         break;
  978.     }
  979.     (void) fclose(fp);
  980.     if (error)
  981.         Message("<Error occured while writing to file.>", 0);
  982.     else
  983.         Message("File written.", 0);
  984.     }
  985. }
  986.  
  987. /*
  988.  * Load
  989.  */
  990.  
  991. /*
  992.  * Load calls three auxiliary routines.  Each takes an open FILE *
  993.  * and returns a count of how many colors it read in, or:
  994.  *     0 to indicate that the file is not of the required type.
  995.  *    -1 to indicate that it's the right type but an error occurred
  996.  *       before any loading took place.
  997.  *    -2 the colormap was partially loaded when an error occurred
  998.  *       (this is bogus).
  999.  * The subroutine displays an error message whenever -1 or -2 is returned.
  1000.  */
  1001.  
  1002. static void Load()
  1003. {
  1004.     void UpdateColorMaps();
  1005.     int Load_NumList(), Load_Rasterfile(), Load_C_Array();
  1006.  
  1007.     FILE *fp;
  1008.     int ccount;
  1009.  
  1010.     if (cur_size == 2)
  1011.     Message("<Error: Can't load into a 2 color map.>", 0);
  1012.     if (fp = fopen(panel_get_value(file_name), "r")) {
  1013.     if ((ccount = Load_NumList(fp)) == 0) {
  1014.         rewind(fp);
  1015.         if ((ccount = Load_Rasterfile(fp)) == 0) {
  1016.         rewind(fp);
  1017.         if ((ccount = Load_C_Array(fp)) == 0)
  1018.             Message("<Error: Couldn't find any colors in file.>", 0);
  1019.         }
  1020.     }
  1021.     if (ccount > 0)
  1022.         Message("<Loaded %d color map from file.>", ccount);
  1023.     if (ccount > 0 || ccount == -2)
  1024.         UpdateColorMaps(U_NEW_COLOR);
  1025.     (void) fclose(fp);
  1026.     }
  1027.     else
  1028.     Message("<Error: Couldn't open specified file>", 0);
  1029. }
  1030.  
  1031.  
  1032. static int Load_NumList(fp)
  1033. FILE *fp;
  1034. {
  1035.     int tem1, tem2, tem3;
  1036.     int i;
  1037.  
  1038.     for(i = -1; 
  1039.         fscanf(fp, "%d %d %d", &tem1, &tem2, &tem3) == 3 &&
  1040.         ++i < cur_size; ) {
  1041.     *(cur_map.cm_red + i) = tem1;
  1042.     *(cur_map.cm_green + i) = tem2;
  1043.     *(cur_map.cm_blue + i) = tem3;
  1044.     }
  1045.     if (i == cur_size) {
  1046.     Message("<Error: Only the first %d colors fit.>", i);
  1047.     return(-2);
  1048.     }
  1049.     else
  1050.     return(i == -1 ? 0 : i+1);
  1051. }
  1052.  
  1053.  
  1054. static int Load_Rasterfile(fp)
  1055. FILE *fp;
  1056. {
  1057.     struct rasterfile rh;
  1058.     colormap_t colormap;
  1059.     enum {NOT_A_RASTERFILE, DID_GOOD, ERROR} status = ERROR;
  1060.     boolean isa_rasterfile = true;
  1061.  
  1062.     if (pr_load_header(fp, &rh) == PIX_ERR)
  1063.     status = NOT_A_RASTERFILE;
  1064.     else if (rh.ras_maplength == 0 || rh.ras_maptype == RMT_NONE)
  1065.     Message("<Error: File's colormap is empty.>", 0);
  1066.     else if (rh.ras_maptype != RMT_EQUAL_RGB)
  1067.     Message("<Error: File's colormap not of type RMT_EQUAL_RGB", 0);
  1068.     else if ((colormap.length = rh.ras_maplength / 3) > cur_size)
  1069.     Message("<Error: Can't fit %d colors into current map>",
  1070.         colormap.length);
  1071.     else {
  1072.     colormap.type = RMT_EQUAL_RGB;
  1073.     colormap.map[0] = cur_map.cm_red;
  1074.     colormap.map[1] = cur_map.cm_green;
  1075.     colormap.map[2] = cur_map.cm_blue;
  1076.     /* Note colormap.length set above */
  1077.     if (pr_load_colormap(fp, &rh, &colormap) == PIX_ERR)
  1078.         Message("<Major bummer: Error while reading the colormap.>", 0);
  1079.     else
  1080.         status = DID_GOOD;
  1081.     }
  1082.     
  1083.     return((status==DID_GOOD ? colormap.length :
  1084.         (status==NOT_A_RASTERFILE ? 0 : -1)));
  1085. }
  1086.  
  1087. static int Load_C_Array(fp)
  1088. FILE *fp;
  1089. {
  1090.     char buf[BUFSIZ];
  1091.     char *targ, *ptr;
  1092.     int rgb, ccolor = 0;
  1093.     boolean in_comment = false;
  1094.     unsigned char *cur_array;
  1095.  
  1096.     do {
  1097.     do {
  1098.         if (ptr = fgets(buf, BUFSIZ, fp))
  1099.         for (targ = "char red[", ptr = buf; *targ && *ptr; )
  1100.             if (*ptr++ == *targ)
  1101.             ++targ;
  1102.     } while (ptr && (*targ != '\0'));
  1103.     } while (ptr && !index(ptr, '='));
  1104.     
  1105.     if (ptr) {            /* Hey, we found our target! */
  1106.     for (rgb = -1; ++rgb < 3; ) {
  1107.         ccolor = 0;
  1108.         cur_array = (rgb == 0 ? cur_map.cm_red :
  1109.              (rgb == 1 ? cur_map.cm_green :
  1110.               cur_map.cm_blue));
  1111.         while (*ptr != '{')
  1112.         if (*ptr == '\0') {
  1113.             ptr = fgets(buf, BUFSIZ, fp);
  1114.             if (ptr == NULL) {
  1115.             Message("<Error: EOF in color array.>", 0);
  1116.             return(rgb == 0 ? -1 : -2);
  1117.             }
  1118.         }
  1119.         else
  1120.             ++ptr;
  1121.  
  1122.         if (*ptr) {        /* Found the open brace. */
  1123.         while (1) {
  1124.             /* Get a new line when you finish one */
  1125.             if (*ptr == '\0') {
  1126.             ptr = fgets(buf, BUFSIZ, fp);
  1127.             if (ptr == NULL) {
  1128.                 Message("<Error: EOF in color array.>", 0);
  1129.                 return(-2);
  1130.             }
  1131.             }
  1132.             if (*ptr == '}')
  1133.             break;
  1134.  
  1135.             /* Look for comments */
  1136.             if (*ptr == '/' && *(ptr+1) == '*')
  1137.             in_comment = true;
  1138.             if (*ptr == '*' && *(ptr+1) == '/')
  1139.             in_comment = false;
  1140.             
  1141.             /* This is a number, read it */
  1142.             if (!in_comment && isdigit(*ptr)) {
  1143.             *(cur_array + ccolor++) = atoi(ptr);
  1144.             while (isdigit(*++ptr))
  1145.                 ;
  1146.             }
  1147.             else
  1148.             ++ptr;
  1149.         }
  1150.         }
  1151.     }
  1152.     }
  1153.     return(ccolor);
  1154. }
  1155.  
  1156.  
  1157.  
  1158. /* 
  1159.  * Quit
  1160.  */
  1161.  
  1162. static void Quit()
  1163. {
  1164.     exit(0);
  1165. }
  1166.  
  1167.  
  1168. /* 
  1169.  * Reread_Maps - Do a brute force reread of the colormaps.  Delete 
  1170.  *               everything in the hash table and the table_panel.  Then 
  1171.  *               walk down the tree the same as at startup (except this 
  1172.  *               time, our windows are in the tree).
  1173.  */
  1174.  
  1175. static void Reread_Maps(item, event)
  1176. Panel_item item;
  1177. Event *event;
  1178. {
  1179.     int Get_Root();
  1180.     boolean WalkWinTree();
  1181.     void SelectCMS();
  1182.     char *item_name;
  1183.     int rootfd;
  1184.     
  1185.     if (panel_get_value(reset_on_reread)==0) {
  1186.     panel_each_item(table_panel, item)
  1187.         item_name = (char *) panel_get(item, PANEL_LABEL_STRING);
  1188.     *(rindex(item_name, '[')-1) = '\0';
  1189.     H_Delete(item_name);
  1190.     panel_destroy_item(item);
  1191.     panel_end_each
  1192.     }
  1193.     if ((rootfd=Get_Root(control_panel))==-1)
  1194.     Message("<Error: Couldn't open root window device.>", 0);
  1195.     else {
  1196.     if (!WalkWinTree(rootfd, shallow_walkP))
  1197.         Message("<Error: CMS table full.  Not all windows processed.>", 0);
  1198.     (void) close(rootfd);
  1199.     if (H_Member(cur_name, NIL(struct cms_map), NIL(Panel_item *)))
  1200.         item_name = cur_name;
  1201.     else
  1202.         item_name = frame_cms_name;
  1203.     
  1204.     cur_name = NULL;
  1205.     SelectCMS(item_name);
  1206.     panel_paint(table_panel, PANEL_CLEAR);
  1207.     }
  1208. }
  1209.  
  1210.  
  1211. /* 
  1212.  * MakeCMS - Create a new entry as specified by the two params and 
  1213.  *           return true if it doesn't already exist.  Otherwise, do 
  1214.  *           nothing and return false.
  1215.  */
  1216.  
  1217. boolean MakeCMS(cmsdata, themap)
  1218. struct colormapseg *cmsdata;
  1219. struct cms_map *themap;
  1220. {
  1221.     char buf[CMS_NAMESIZE+6];
  1222.     char *ptr;
  1223.     Panel_item item;
  1224.  
  1225.     (void) sprintf(buf, "%s [%d]", cmsdata->cms_name, cmsdata->cms_size);
  1226.     
  1227.     for (ptr=buf+strlen(buf); ptr < buf+CMS_NAMESIZE+6-5; ++ptr)
  1228.     *ptr = ' ';
  1229.     *ptr = '\0';
  1230.  
  1231.     item = panel_create_item(table_panel, PANEL_MESSAGE,
  1232.                  PANEL_LABEL_STRING, buf,
  1233.                  0);
  1234.     if (H_Insert(cmsdata->cms_name, cmsdata->cms_size, item, themap)==false) {
  1235.     panel_destroy_item(item);
  1236.     return(false);
  1237.     }
  1238.     else
  1239.     return(true);
  1240. }
  1241.  
  1242.  
  1243. /* 
  1244.  * ClickOnCMS - Find out which colormap name was clicked on and make it 
  1245.  *              the current color.
  1246.  *              If it was shift-clicked, delete it from the table.
  1247.  */
  1248.  
  1249. static void ClickOnCMS(item, event)
  1250. Panel_item item;
  1251. Event *event;
  1252. {
  1253.     void SelectCMS();
  1254.     static char buf[CMS_NAMESIZE+6]; /* static so cur_name can point to it. */
  1255.  
  1256.     if (event_id(event) == MS_LEFT && event_is_down(event)) {
  1257.     (void) strcpy(buf, panel_get(item, PANEL_LABEL_STRING));
  1258.     *(rindex(buf, '[')-1) = '\0';
  1259.     if (event_shift_is_down(event)) {
  1260.         if (!strcmp(buf, frame_cms_name))
  1261.         Message("<Error: Can't delete Palette's colormap>", 0);
  1262.         else {
  1263.         Message("", 0);
  1264.         if (item == cur_cms_item)
  1265.             SelectCMS(frame_cms_name);
  1266.         H_Delete(buf);
  1267.         panel_destroy_item(item);
  1268.         panel_paint(table_panel, PANEL_CLEAR);
  1269.         }
  1270.     }
  1271.     else
  1272.         SelectCMS(buf);
  1273.     }
  1274. }
  1275.  
  1276.  
  1277. /* 
  1278.  * ResizeCanvas - Call the canvas.c package routine when the canvas size 
  1279.  *                changes.  Then redraw the palette.  Also if necessary, 
  1280.  *                call the routine which defends against a window system 
  1281.  *                bug.  See BorrowFramesCMS() for details.
  1282.  */
  1283.  
  1284. static void ResizeCanvas()
  1285. {
  1286.     extern void SetPaletteSize();
  1287.     void BorrowFramesCMS();
  1288.     boolean glob_use = use_colormap;
  1289.     char *glob_name = cur_name;
  1290.  
  1291.     SetPaletteSize();
  1292.     use_colormap = false;    /* So Palette's other win's don't redraw, too */
  1293.     if (cur_size > 2)
  1294.     BorrowFramesCMS();
  1295.     SelectCMS(glob_name);
  1296.     use_colormap = glob_use;
  1297. }
  1298.  
  1299.  
  1300.     
  1301. /* 
  1302.  * CanvasEvent - Do the right thing with the variety of left- and 
  1303.  *               right-clicks, and drags.
  1304.  */
  1305.  
  1306. static void CanvasEvent(win, event, arg)
  1307. Window win;
  1308. Event *event;
  1309. caddr_t arg;
  1310. {
  1311.     extern void DrawPalette(), BoxSwatches();
  1312.     extern int WhichSwatch();
  1313.     void SelectEntry();
  1314.     int selection;
  1315.  
  1316.     if (event_id(event) == LOC_DRAG || event_is_button(event)) {
  1317.     selection = WhichSwatch(event_x(event), event_y(event));
  1318.     if (selection < 0)  /* Clicking outside the rect erases the selection */
  1319.         DrawPalette(cur_size);
  1320.     else if (selection != cur_range_end && selection != cur_entry &&
  1321.          ((event_id(event) == MS_MIDDLE && event_is_down(event)) ||
  1322.           (event_id(event) == MS_LEFT && event_is_up(event)) ||
  1323.           event_id(event) == LOC_DRAG))
  1324.         SelectEntry(cur_entry, selection);
  1325.     else if (event_id(event) == MS_LEFT && event_is_down(event)) {
  1326.         SelectEntry(selection, -1);
  1327.     }
  1328.     }
  1329. }
  1330.  
  1331.  
  1332. /* 
  1333.  * SelectCMS - Get the specs for a colormap, and make it the current one. 
  1334.  *             Note, that there should never be an error, since if a map 
  1335.  *             isn't in the table, the user should have no way to get it 
  1336.  *             to here.
  1337.  */
  1338.  
  1339. static void SelectCMS(name)
  1340. char *name;
  1341. {
  1342.     extern void DrawPalette();
  1343.     void UpdateColorMaps();
  1344.  
  1345.     int size;
  1346.  
  1347.     if (cur_name)
  1348.     panel_set(cur_cms_item, PANEL_LABEL_BOLD, FALSE, 0);
  1349.     if (size = H_Member(name, &cur_map, &cur_cms_item)) {
  1350.     cur_size = size;
  1351.     cur_name = name;
  1352.     panel_set(cur_cms_item, PANEL_LABEL_BOLD, TRUE, 0);
  1353.     UpdateColorMaps(U_NEW_CMS);
  1354.     SelectEntry(cur_entry >= cur_size ? 0 : cur_entry,
  1355.            cur_range_end >= cur_size ? -1 : cur_range_end);
  1356.     }
  1357.     else
  1358.     Message("<Weird error: Colormap not in hash table.>", 0);
  1359. }
  1360.  
  1361.  
  1362.  
  1363.  
  1364. /* 
  1365.  * BorrowFramesCMS - SunOS 3.4 apparently gets troubled by deep 
  1366.  *                   pixrects and by changes made to a retained pixwin 
  1367.  *                   behind its back.  Specifically, when a canvas gets 
  1368.  *                   resized, the backing pixrect (pw_prretained) gets
  1369.  *                   set to a depth of 1 even for 8 bit deep pixwins.
  1370.  *                   If a color window gets set back to its original 
  1371.  *                   color, the scrollbar color gets messed up.  Also, 
  1372.  *                   when changing a window's icon from an 8-bit to a 
  1373.  *                   one bit, two WINGETCMS ioctl errors are generated.
  1374.  *                   
  1375.  *                   This routine protects against that by allowing 
  1376.  *                   callers to borrow the frame's original colormap 
  1377.  *                   before doing any the above operations.  It's a 
  1378.  *                   nasty kludge, and a lousy description of the 
  1379.  *                   problem.  But, hey, get outta my face.
  1380.  */
  1381.  
  1382. static void BorrowFramesCMS()
  1383. {
  1384.     void SelectCMS();
  1385.  
  1386.     int glob_entry = cur_entry;
  1387.     int glob_range_end = cur_range_end;
  1388.  
  1389.     SelectCMS(frame_cms_name);
  1390.     cur_entry = glob_entry;    /* In case it was reset to 0 in SelectCMS() */
  1391.     cur_range_end = glob_range_end;
  1392. }
  1393.  
  1394.