/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "imtool.h" /* * IMTOOL -- Software image display for the Sun workstation under Sunview. * A variable sized window is used to peer into a "fixed" size frame buffer * at an arbitrary offset (pan) and scale (zoom/dezoom). The number of frames * and the size of a frame buffer is arbitrary and is a setup option. The * depth of a frame on an 8 bit display is 7 bits with a 1 bit graphics * overlay plane; this leaves almost half of the color table space for use * by other windows. A data stream command interface is provided for software * control of the display server by other processes, not necessarily on the * same node. * * D.Tody, April 1987 (NOAO/IRAF project) * Extensively revised and extended December 1987. * Zoom and further datastream mods (WCS) added May 1989. * (but NeWS/X is coming soon and probably none of this will work anymore...) */ #ifndef abs #define abs(a) (((a)<0)?(-(a)):(a)) #endif #ifndef min #define min(a,b) ((a)<(b)?(a):(b)) #endif #ifndef max #define max(a,b) ((a)<(b)?(b):(a)) #endif /* Default values, size limiting values. */ #define MAX_ARGS 50 /* max command line arguments */ #define MAX_FBCONFIG 128 /* max possible frame buf sizes */ #define MAX_FRAMES 16 /* max number of frames */ #define FRAME_CHOICES "1","2","3","4" /* nframes choices for setup */ #define NGREY 256 /* max physical greylevels */ #define CLOCK_INTERVAL 500 /* main clock tick, msec */ #define DEF_NCONFIG 1 /* number of f.b. configs */ #define DEF_NFRAMES 1 /* save memory; only one frame */ #define DEF_FRAME_WIDTH 512 /* 512 square frame */ #define DEF_FRAME_HEIGHT 512 /* 512 square frame */ #define DEF_GIOWIN_SIZE 512 /* default size gio window */ #define SZ_LABEL 256 /* main frame label string */ #define SZ_IMTITLE 128 /* image title string */ #define SZ_WCTEXT 80 /* WCS box text */ #define SZ_WCSBUF 320 /* WCS text buffer size */ #define SZ_PANTEXT 18 /* displayed chars in o_fname */ #define SZ_COLORBAR 11 /* height of colorbar in pixels */ #define SZ_FNAME 128 #define SZ_LINE 256 #define IO_TIMEOUT 30 /* i/o not getting anywhere */ #define SZ_FIFOBUF 4000 /* transfer size for FIFO i/o */ #define BKG_WHITE 0 #define BKG_BLACK 1 #define P_IMAGE 1 #define P_GRAPHICS 2 #define P_COLORBAR 4 #define P_DONTCLIP 8 #define PANNER_EVENT 99 #define INTERRUPT 003 #define NEXT_SCREEN 006 #define PREV_SCREEN 022 #define CYCLE_BLINK 002 /* Reserved colormap entries. */ #define CMS_DATASTART 1 /* first data greylevel */ #define CMS_DATAEND 200 /* last data greylevel */ #define CMS_DATARANGE 200 /* number of data greylevels */ #define CMS_CURSOR 201 /* cursor color table entry */ #define CMS_BACKGROUND 202 /* background color */ #define CMS_GRAPHICSSTART 203 /* first graphics greylevel */ #define CMS_GRAPHICSEND 217 /* last graphics greylevel */ #define CMS_GRAPHICSRANGE 15 /* number of graphics greylevel */ #define CMS_GCOLOR(c) (203+(c)) /* graphics color table entries */ #define CMS_FIRST 1 /* first grey level used */ #define CMS_NGREY 218 /* total number of grey levels */ /* Magic numbers. */ #define BLINK_OFF 1 /* crosshair cursor off */ #define BLINK_ON 2 /* turn crosshair cursor on */ #define CMMAPNAME "imtool" /* color map segment name */ #define OLD_DEVNAME "/dev/imt1" /* original pseudodevice name */ #define I_DEVNAME "/dev/imt1o" /* pseudo device names */ #define O_DEVNAME "/dev/imt1i" /* our IN is client's OUT */ #define KEY_SETUP KEY_TOP(4) /* togglt the setup panel */ #define KEY_REMARK KEY_TOP(5) /* remark list of objects */ #define KEY_PCOORDS KEY_TOP(6) /* cont. coords display */ #define KEY_SNAP KEY_TOP(7) /* image hardcopy key */ #define TEXT_FONT "/usr/lib/fonts/fixedwidthfonts/screen.b.14" #define MARK_FONT "/usr/lib/fonts/fixedwidthfonts/screen.r.11" #define COORDFILE "frame.%d.%d" #define FBCONFIG_1 ".imtoolrc" #define FBCONFIG_2 "/usr/local/lib/imtoolrc" #define FBCONFIG_ENV1 "imtoolrc" #define FBCONFIG_ENV2 "IMTOOLRC" #define R_TYPE 0 /* 0=postscript, 1=rasterfile */ #define R_DISPOSE "lpr -s %s" /* dispose command */ #define R_FILENAME "" /* output filename */ /* Global state codes. */ #define TRACK_CURSOR 0 #define WINDOW 1 #define ROAM 2 #define MONO 0 #define HEAT 1 #define RAMP1 2 #define RAMP2 3 #define HALLEY 4 #define LINEARPS 5 #define RANDOMPS 6 #define CRANDOMPS 7 #define ULUT1 8 #define ULUT2 9 /* WCS definitions. */ #define W_UNITARY 0 #define W_LINEAR 1 #define W_LOG 2 #define W_DEFFORMAT " %7.2f %7.2f %7.1f%c" /* Internal variables. */ static int snap_frame_too = 1; /* include frame in imcopy? */ static int cursor_blink = -1; /* crosshair or small cursor */ static int cursor_show = -1; /* cursor state; on/off */ static int display_coords = 0; /* cont. display cursor coords */ static int p_cursor_setback = 0; /* restore cursor pos after pan */ static int panning = 0; /* smooth image pan in progress */ static int maptype = MONO; /* initial mapping type */ static char o_fname[SZ_FNAME]; /* name of coord output file */ static char o_revtext=1; /* reverse video text? */ static int setup_xoff = 4; /* offset to setup panel */ static int setup_yoff = 18; /* " " */ static int wc_xoff=0, wc_yoff=0; /* offset to WCS output box */ static int wc_width, wc_height; /* size of WCS output box */ static char wc_text[SZ_WCTEXT+1]; /* coordinate text */ static struct pixfont *wc_font = NULL; /* WCS box font */ static int cb_height = SZ_COLORBAR; static int show_colorbar = 1; static int black = 0; static int white = NGREY - 1; static int background = 0; /* background color index */ static int state = TRACK_CURSOR; /* mouse button state */ static int last_sx, last_sy; /* window x,y of last event */ static int save_sx, save_sy; /* save absolute mouse position */ static int last_bx, last_by; /* last button press */ static int fb_bkgcolor_index = BKG_WHITE; static int window_open = 1; static int global_colortable = 1; /* globally manage colortable */ static int fbconfig = 0; static int last_x, last_y, last_key, key_left=0; static int reading_imcursor = 0; static int imcursor_wcs; static char wcsbuf[MAX_FRAMES][SZ_WCSBUF]; #define CRANDOM_CHOICES "1", "2", "4", "8", "16", "32" static int cr_msec[] = { 1000, 2000, 4000, 8000, 16000, 32000 }; static int crandom_blink_rate = 1; /* rate for cont. random pseudo */ /* Blink parameters. */ #define BLINKRATE_CHOICES "1/2","1","2","4","8","16","32" static int blink_rate[] = { 1, 2, 4, 8, 16, 32, 64 }; static int blink_rate_index = 1; /* current blink rate */ static int blink_timer = 0; /* nticks left on clock */ static int blink_frame = 0; /* current blink frame */ static int blink = 0; /* blink enabled? */ static int n_blink_frames = 8; /* number of frames to blink */ static int blink_frames[MAX_FRAMES] = { 1, 2, 3, 4, 5, 6, 7, 8 }; static char s_blinklist[SZ_FNAME+1] = "all"; /* list of frames to blink */ /* Logical image cursor parameters. */ static int marktype = 0; /* mark cursor position */ /* The following is needed to provide sufficient precision to allow for * zooming virtual pixrects (Rects use type short). */ typedef struct bigrect { int r_left, r_top; int r_width, r_height; } BRect; /* Predefined lookup tables. */ struct triplet { float red, green, blue; }; struct lut { int lutlen; struct triplet hue[NGREY]; }; struct lut heat = { #include "heat.lut" }; struct lut halley = { #include "halley.lut" }; /* User defined lookup tables. */ static char u_lut1[SZ_FNAME+1] = "none"; static char u_lut2[SZ_FNAME+1] = "none"; static BRect pw_rect; /* raw frame buffer */ static int fb_depth = 8; static int fb_ngrey = CMS_DATARANGE; static int fb_nframes= DEF_NFRAMES; static int Fb_width = DEF_FRAME_WIDTH; static int Fb_height = DEF_FRAME_HEIGHT; static BRect fb_rect; /* zoomed frame buffer */ static int fb_width = DEF_FRAME_WIDTH; static int fb_height = DEF_FRAME_HEIGHT; #define MAX_ZOOMS 8 #define ZOOM_CHOICES "1","2","4","8" static int zoom = 1; static int nzooms = 4; /* number of zoom factors */ static int zoom_index = 0; static int zooms[MAX_ZOOMS] = { 1, 2, 4, 8 }; static char s_zoomslist[SZ_FNAME+1] = "1 2 4 8"; static int gio_xsize = DEF_GIOWIN_SIZE; static int gio_ysize = DEF_GIOWIN_SIZE; static int initial_gio_xsize, initial_gio_ysize; /* Rotation matrix defining world coordinate system (WCS) of a frame. */ struct ctran { int valid; /* has WCS been set? */ float a, b; /* x, y scale factors */ float c, d; /* x, y cross factors */ float tx, ty; /* x, y translation */ float z1, z2; /* greyscale range */ int zt; /* greyscale mapping */ char format[32]; /* wcs output format */ char imtitle[SZ_IMTITLE+1]; /* image title from WCS */ }; /* The frame buffers. */ struct framebuf { struct pixrect *fb_pr; /* frame buffer pixrect */ int fb_frameno; /* frame number */ int fb_xoff, fb_yoff; /* fb coords of pixwin (0,0) */ int fb_xzoom, fb_yzoom; /* zoom/dezoom factors */ int fb_objno; /* object number */ int fb_imageno; /* displayed frame counter */ int fb_maptype; /* greyscale transformation */ float fb_center, fb_slope; /* transfer function */ struct ctran fb_ctran; /* world coordinate system */ char fb_label[SZ_LABEL+1]; /* frame label string */ }; /* Possible frame buffer sizes. */ struct fbconfig { int nframes; /* number of frames */ int width; /* frame buffer width */ int height; /* frame buffer height */ }; static int display_frame; /* currently displayed frame */ static int reference_frame; /* reference (cmd i/o) frame */ static struct framebuf *frames=NULL; /* array of frame descriptors */ static struct framebuf *df_p; /* display frame descriptor */ static struct framebuf *rf_p; /* reference frame descriptor */ static struct pixrect *cb_pr; /* colorbar pixrect */ static int fb_nconfig = 0; static int fb_config_index = 0; static struct fbconfig fb_config[MAX_FBCONFIG]; static char startfile[SZ_FNAME+1]; /* image read on startup */ static char rasterfile[SZ_FNAME+1] = "raster.%d.%d"; /* Screendump stuff. */ int r_type = R_TYPE; char r_dispose[SZ_FNAME+1] = R_DISPOSE; char r_filename[SZ_FNAME+1] = R_FILENAME; #define HEIGHTADJUST \ (tool_headerheight((int)window_get(gio_frame, FRAME_SHOW_LABEL)) + \ TOOL_BORDERWIDTH) static short iconimage[] = { #include "imtool.icon" }; DEFINE_ICON_FROM_IMAGE (icon, iconimage); Window gio_frame, gio_canvas; static int gio_frame_fd; static int datain, dataout; static Menu_item blink_item; static Panel setup_panel; static Window setup_frame; static Panel_item pan_show_colorbar, pan_globalcolor; static Panel_item pan_set_nframes, pan_blink_rate, pan_blink_list; static Panel_item pan_set_maptype, pan_crandom_rate, pan_set_ofname; static Panel_item pan_snapframetoo, pan_set_background, pan_set_rfname; static Panel_item pan_set_rtype, pan_set_rdispose, pan_set_rfilename; static Panel_item pan_set_marker, pan_zoom_list; static Panel_item pan_set_ulut1, pan_set_ulut2; static unsigned char red[NGREY], blue[NGREY], green[NGREY]; static unsigned char m_red[NGREY], m_blue[NGREY], m_green[NGREY]; static struct pixwin *gio_pw; static int main_argc, gio_argc; static char **main_argv, *gio_argv[MAX_ARGS]; static Notify_value ev_gioframe(), set_colortable(); static Notify_value ev_gioinput(), ev_cmdinput(), ev_panner(); static char *getfname(), *framelabel(); static struct ctran *wcs_update(); static struct pixrect *get_screen_rect(); static refresh_display(); extern char *getenv(); /* IMTOOL_MAIN -- Create the Imtool windows, i.e., the main display window, * the region of interest or "cursor" subwindow, and the setup panel. There * are two principal event handlers, the display window event handler, used * to process cursor input and mouse button commands, and the command input * event handler, used to communicate with the client process. */ #ifdef STANDALONE main (argc, argv) #else imtool_main (argc, argv) #endif int argc; char **argv; { char *s; main_argc = argc; main_argv = argv; parse_args (argc, argv, &gio_argc, gio_argv); /* Screendump stuff. */ if (s = getenv ("R_DISPOSE")) strcpy (r_dispose, s); if (s = getenv ("R_FILENAME")) strcpy (r_filename, s); if (s = getenv ("R_RASTERFILE")) { strcpy (r_filename, s); r_type = 1; } gio_frame = window_create (NULL, FRAME, FRAME_ICON, &icon, FRAME_LABEL, "imtool - NOAO/IRAF Sunview Image Display V1.1", FRAME_ARGS, gio_argc, gio_argv, FRAME_NO_CONFIRM, FALSE, 0); if (gio_frame == NULL) exit (1); gio_frame_fd = (int) window_get (gio_frame, WIN_FD); parse_args (argc, argv, &gio_argc, gio_argv); create_gio_canvas (gio_argc, gio_argv); create_frame_menu (gio_frame); create_setup_popup(); notify_interpose_event_func (gio_frame, ev_gioframe, NOTIFY_SAFE); notify_interpose_event_func (gio_canvas, ev_gioinput, NOTIFY_SAFE); get_fbconfig(); set_fbconfig (fbconfig, 0); load_testpattern (0); set_colortable(); gio_setcursor (CURSOR_ON, BLINK_OFF); set_transfer_function (gio_pw, df_p->fb_center, df_p->fb_slope); Bpw_get_region_rect (gio_pw, &pw_rect); pw_rect.r_left = df_p->fb_xoff; pw_rect.r_top = df_p->fb_yoff; init_colorbar (pw_rect.r_width); if (startfile[0]) load_raster (rf_p->fb_pr, startfile); initial_gio_xsize = gio_xsize; initial_gio_ysize = gio_ysize; /* Open the output fifo. We have to open it ourselves first as a * client to get around the fifo open-no-client error. */ if ((datain = open (O_DEVNAME, O_RDONLY|O_NDELAY)) != -1) { if ((dataout = open (O_DEVNAME, O_WRONLY|O_NDELAY)) != -1) fcntl (dataout, F_SETFL, O_WRONLY); close (datain); } /* Open the input stream, a FIFO pseudodevice file used by * applications to send us commands and data. */ if ((datain = open (I_DEVNAME, O_RDONLY|O_NDELAY)) == -1) { if ((datain = open (OLD_DEVNAME, O_RDONLY|O_NDELAY)) == -1) fprintf (stderr, "Warning: cannot open %s\n", I_DEVNAME); } else { /* Clear O_NDELAY for reading. */ fcntl (datain, F_SETFL, O_RDONLY); notify_set_input_func (gio_frame, ev_cmdinput, datain); } imtool_clock(); window_main_loop (gio_frame); close (datain); exit (0); } /* PARSE_ARGS -- Parse the argument list into the arguments for the main frame * and the global arguments for the server. */ static parse_args (argc, argv, gio_argc, gio_argv) int argc; char *argv[]; int *gio_argc; char *gio_argv[]; { register char *argp; register int arg; static int ncalls = 0; gio_argv[0] = argv[0]; *gio_argc = 1; for (arg=1; arg <= argc && (argp = argv[arg]) != NULL; arg++) { if (strncmp (argp, "-fbconfig", 3) == 0) { /* Set the frame buffer configuration. */ if ((argp = argv[arg+1]) && isdigit(*argp)) { fbconfig = max (0, atoi(argp) - 1); arg++; } else if (ncalls == 0) fprintf (stderr, "-fbconfig argument missing\n"); } else if (strncmp (argp, "-raster", 4) == 0) { if ((argp = argv[arg+1])) { strcpy (startfile, argp); arg++; } } else gio_argv[(*gio_argc)++] = argp; } gio_argv[(*gio_argc)] = NULL; ncalls++; } /* GET_FBCONFIG -- Read the IMTOOL startup file to get the set of possible * frame buffer sizes. * * File format: configno nframes width height [extra fields] * e.g., 1 2 512 512 * 2 2 800 800 * 3 1 1024 1024 # comment */ static get_fbconfig() { register char *ip; register FILE *fp; int config, nframes, width, height, i; char lbuf[SZ_LINE+1], *fname; /* Initialize the config table. */ for (i=0; i < MAX_FBCONFIG; i++) fb_config[i].nframes = 0; /* Attempt to open the config file. */ fp = NULL; if ((fname=getenv(FBCONFIG_ENV1)) || (fname=getenv(FBCONFIG_ENV2))) fp = fopen (fname, "r"); if (!fp && (fname = getenv ("HOME"))) { sprintf (lbuf, "%s/%s", fname, FBCONFIG_1); fp = fopen (fname = lbuf, "r"); } if (!fp) fp = fopen (fname = FBCONFIG_2, "r"); /* If cannot find a config file, set up the default configuration. */ if (!fp) { fb_config_index = fbconfig = 0; fb_nconfig = DEF_NCONFIG; fb_config[0].nframes = DEF_NFRAMES; fb_config[0].width = DEF_FRAME_WIDTH; fb_config[0].height = DEF_FRAME_HEIGHT; return; } /* Scan the frame buffer configuration file. */ fb_nconfig = 0; while (fgets (lbuf, SZ_LINE, fp) != NULL) { /* Skip comment lines and blank lines. */ for (ip=lbuf; *ip == ' ' || *ip == '\t'; ip++) ; if (*ip == '\n' || *ip == '#') continue; if (!isdigit (*ip)) continue; switch (sscanf (ip, "%d%d%d%d", &config,&nframes,&width,&height)) { case 4: break; /* normal case */ case 3: height = width; /* default to square format */ break; default: fprintf (stderr, "imtool: bad config `%s'\n", ip); continue; } nframes = max (1, nframes); width = max (1, width); height = max (1, height); /* Since the frame buffer is stored in a memory pixrect * (effectively), the line length should be an integral number * of 16 bit words. */ if (width & 1) { fprintf (stderr, "imtool warning: fb config %d [%d-%dx%d] - ", config, nframes, width, height); fprintf (stderr, "frame width should be even, reset to %d\n", --width); } config = max(1, min(MAX_FBCONFIG, config)) - 1; fb_config[config].nframes = nframes; fb_config[config].width = width; fb_config[config].height = height; fb_nconfig = max (fb_nconfig, config+1); } fclose (fp); } /* SET_FBCONFIG -- Setup a frame buffer configuration. */ static set_fbconfig (config, nframes) int config; int nframes; { register struct pixrect *pr = get_screen_rect(); int old_config = fb_config_index; int old_nframes = fb_nframes; char text[SZ_LINE]; if (config < 0 || config >= fb_nconfig) { fprintf (stderr, "imtool: no such frame buffer configuration - %d\n", config+1); return; } else if (nframes <= 0) nframes = fb_config[config].nframes; if (init_framebuffers (config, nframes) == -1) { fprintf (stderr, "restore configuration %d\n", old_config + 1); if (init_framebuffers (old_config, old_nframes) == -1) { fprintf (stderr, "cannot restore frame buffer configuration - imtool dies\n"); exit (1); } } if (gio_xsize <= 0 || gio_xsize > Fb_width) gio_xsize = Fb_width; if (gio_ysize <= 0 || gio_ysize > (Fb_height + cb_height)) gio_ysize = Fb_height + cb_height; gio_xsize = min (pr->pr_width - TOOL_BORDERWIDTH * 2, gio_xsize); gio_ysize = min (pr->pr_height - tool_headerheight ((int)window_get(gio_frame,FRAME_SHOW_LABEL)) - TOOL_BORDERWIDTH, gio_ysize); window_set (gio_canvas, WIN_WIDTH, gio_xsize, WIN_HEIGHT, gio_ysize, 0); window_fit (gio_canvas); window_fit (gio_frame); Bpw_get_region_rect (gio_pw, &pw_rect); pw_rect.r_left = df_p->fb_xoff; pw_rect.r_top = df_p->fb_yoff; sprintf (text, "Frame buffer configuration %d: %d %dx%d frame%c", fb_config_index + 1, fb_nframes, Fb_width, Fb_height, fb_nframes > 1 ? 's' : ' '); window_set (gio_frame, FRAME_LABEL, text, 0); panel_set_value (pan_set_maptype, df_p->fb_maptype); panel_set_value (pan_set_nframes, fb_nframes - 1); } /* LOAD_RASTER -- Load a rasterfile into the display. */ static load_raster (o_pr, fname) Pixrect *o_pr; char *fname; { FILE *fp; Pixrect *i_pr; int width, height; if ((fp = fopen (fname, "r")) == NULL) fprintf (stderr, "cannot open rasterfile %s\n", fname); else { if (i_pr = pr_load (fp, NULL)) { width = min (Fb_width, i_pr->pr_width); height = min (Fb_height, i_pr->pr_height); pr_rop (o_pr, 0, 0, width, height, PIX_SRC, i_pr, 0, 0); pr_close (i_pr); repaint (P_IMAGE|P_COLORBAR|P_GRAPHICS); } fclose (fp); } } /* SAVE_RASTER -- Save a frame buffer in a file. */ static save_raster (i_pr, fname) Pixrect *i_pr; char *fname; { FILE *fp; if ((fp = fopen (fname, "w")) == NULL) fprintf (stderr, "cannot create rasterfile %s\n", fname); else { if (pr_dump (i_pr, fp, RMT_NONE, RT_STANDARD, 0) == PIX_ERR) fprintf (stderr, "error writing rasterfile %s\n", fname); fclose (fp); } } /* CREATE_GIO_CANVAS -- Set up the canvas for the main display window. */ static create_gio_canvas (argc, argv) int argc; char **argv; { register char *argp; register int arg; char pathname[NGREY]; struct pixwin *pw; int name; /* Override the builtin defaults with the values given by the user * on the command line, if any. */ for (arg=1; arg <= argc && (argp = argv[arg]) != NULL; arg++) { if (!strcmp (argp, "-Ws") || !strncmp (argp, "-size", 5)) { gio_xsize = atoi (argv[++arg]) - (TOOL_BORDERWIDTH * 2); gio_ysize = atoi (argv[++arg]) - (tool_headerheight ((int) window_get (gio_frame, FRAME_SHOW_LABEL)) + TOOL_BORDERWIDTH); } else if (!strncmp (argp, "-maptype", 4)) { argp = argv[++arg]; if (!strncmp (argp, "mono", 1)) maptype = MONO; else if (!strncmp (argp, "heat", 1)) maptype = HEAT; else if (!strncmp (argp, "ramp1", 1)) maptype = RAMP1; else if (!strncmp (argp, "ramp2", 1)) maptype = RAMP2; else if (!strncmp (argp, "halley", 1)) maptype = HALLEY; else if (!strncmp (argp, "linear", 1)) maptype = LINEARPS; else if (!strncmp (argp, "random", 1)) maptype = RANDOMPS; else if (!strncmp (argp, "crandom", 1)) maptype = CRANDOMPS; else if (!strncmp (argp, "ulut1", 1)) maptype = ULUT1; else if (!strncmp (argp, "ulut2", 1)) maptype = ULUT2; else fprintf (stderr, "unknown arg `%s' to -maptype\n", argp); } else if (!strncmp (argp, "-nocolorbar", 9)) { cb_height = 0; show_colorbar = 0; } else if (!strncmp (argp, "-colorbar", 7)) { cb_height = SZ_COLORBAR; show_colorbar = 1; } else if (!strncmp (argp, "-black", 3)) { background = CMS_BACKGROUND; fb_bkgcolor_index = BKG_BLACK; } else if (!strncmp (argp, "-white", 3)) { background = 0; fb_bkgcolor_index = BKG_WHITE; } else if (!strncmp (argp, "-rtype", 3)) { argp = argv[++arg]; r_type = (argp[0] == 'r'); } else if (!strncmp (argp, "-rdispose", 3)) { argp = argv[++arg]; strcpy (r_dispose, argp); } else if (!strncmp (argp, "-rfilename", 3)) { argp = argv[++arg]; strcpy (r_filename, argp); } else if (!strncmp (argp, "-ulut1", 6)) { argp = argv[++arg]; strcpy (u_lut1, argp); } else if (!strncmp (argp, "-ulut2", 6)) { argp = argv[++arg]; strcpy (u_lut2, argp); } } /* Open display canvas. The display canvas is never retained at the * pixwin level since we can easily refresh it from the frame buffer. */ gio_canvas = window_create (gio_frame, CANVAS, WIN_WIDTH, gio_xsize, WIN_HEIGHT, gio_ysize, CANVAS_RETAINED, FALSE, CANVAS_AUTO_CLEAR, FALSE, CANVAS_REPAINT_PROC, refresh_display, 0); if (gio_canvas == NULL) exit (1); /* Initialize the frame and lut parameters and the canvax pixwin * color map. */ pw = (struct pixwin *) window_get (gio_canvas, WIN_PIXWIN); fb_depth = pw->pw_pixrect->pr_depth; if (fb_depth < 8) { fprintf (stderr, "imtool cannot be used on monochrome displays\n"); exit (1); } white = (1 << fb_depth) - 1; if ((fb_ngrey = CMS_DATARANGE) > (white + 1)) fb_ngrey = 1; init_colormap (pw); init_colormap (gio_pw = canvas_pixwin (gio_canvas)); /* Set input event flags. */ window_set (gio_canvas, WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS, WIN_MOUSE_BUTTONS, WIN_UP_EVENTS, LOC_DRAG, LOC_WINEXIT, 0, WIN_CONSUME_KBD_EVENTS, WIN_NO_EVENTS, WIN_ASCII_EVENTS, WIN_LEFT_KEYS, WIN_RIGHT_KEYS, KEY_SETUP, KEY_REMARK, KEY_SNAP, KEY_PCOORDS, KBD_DONE, 0, 0); notify_set_event_func (ev_panner, ev_panner, NOTIFY_SAFE); } /* CREATE_SETUP_POPUP -- Create the popup menu used to set the terminal * setup options. */ static create_setup_popup () { extern loadframe_proc(), saveframe_proc(), fitframe_proc(); extern reset_proc(), iclear_proc(), gclear_proc(); extern setup_proc(), toggle_graphics(), set_background(); extern setframe_proc(), blinkenable_proc(), register_proc(); static Panel_setting set_ofname(), set_rfname(); static Panel_setting set_rtype(), set_rdispose(), set_rfilename(); static Panel_setting set_ulut1(), set_ulut2(); static Panel_setting set_blinklist(), set_zoomslist(); static panel_set_item(); setup_frame = window_create (gio_frame, FRAME, FRAME_NO_CONFIRM, TRUE, WIN_X, setup_xoff, WIN_Y, setup_yoff, 0); if (setup_frame == NULL) exit (1); setup_panel = window_create (setup_frame, PANEL, 0); if (setup_panel == NULL) exit (1); panel_create_item (setup_panel, PANEL_MESSAGE, PANEL_ITEM_X, ATTR_COL(10), PANEL_ITEM_Y, ATTR_ROW(0), PANEL_LABEL_STRING, "Image Display Setup and Control", 0); pan_set_nframes = panel_create_item (setup_panel, PANEL_CYCLE, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(1) + 5, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Number of frame buffers: ", PANEL_CHOICE_STRINGS, FRAME_CHOICES, 0, PANEL_VALUE, fb_nframes - 1, PANEL_NOTIFY_PROC, panel_set_item, 0); pan_set_maptype = panel_create_item (setup_panel, PANEL_CYCLE, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(2) + 5, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Greyscale mapping: ", PANEL_CHOICE_STRINGS, "Mono", "ESO-Heat", "Ramp1", "Ramp2", "Halley", "Linear-pseudo", "Random-pseudo", "Crandom-pseudo", "User 1", "User 2", 0, PANEL_VALUE, maptype, PANEL_NOTIFY_PROC, panel_set_item, 0); pan_set_ulut1 = panel_create_item (setup_panel, PANEL_TEXT, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(3) + 8, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "User lookup table 1: ", PANEL_VALUE, u_lut1, PANEL_VALUE_STORED_LENGTH, SZ_FNAME, PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, PANEL_NOTIFY_PROC, set_ulut1, 0); pan_set_ulut2 = panel_create_item (setup_panel, PANEL_TEXT, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(4) + 8, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "User lookup table 2: ", PANEL_VALUE, u_lut2, PANEL_VALUE_STORED_LENGTH, SZ_FNAME, PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, PANEL_NOTIFY_PROC, set_ulut2, 0); pan_globalcolor = panel_create_item (setup_panel, PANEL_CYCLE, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(5) + 8, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Globally manage colortable: ", PANEL_CHOICE_STRINGS, "No", "Yes", 0, PANEL_VALUE, global_colortable, PANEL_NOTIFY_PROC, panel_set_item, 0); pan_crandom_rate = panel_create_item (setup_panel, PANEL_CYCLE, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(6) + 8, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Rate (sec) for crandom option: ", PANEL_CHOICE_STRINGS, CRANDOM_CHOICES, 0, PANEL_VALUE, crandom_blink_rate, PANEL_NOTIFY_PROC, panel_set_item, 0); pan_set_background = panel_create_item (setup_panel, PANEL_CYCLE, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(7) + 8, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Background color: ", PANEL_CHOICE_STRINGS, "white", "black", 0, PANEL_VALUE, fb_bkgcolor_index, PANEL_NOTIFY_PROC, panel_set_item, 0); pan_snapframetoo = panel_create_item (setup_panel, PANEL_CYCLE, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(8) + 8, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Include frame border in imcopy: ", PANEL_CHOICE_STRINGS, "No", "Yes", 0, PANEL_VALUE, snap_frame_too, PANEL_NOTIFY_PROC, panel_set_item, 0); pan_show_colorbar = panel_create_item (setup_panel, PANEL_CYCLE, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(9) + 8, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Show colorbar: ", PANEL_CHOICE_STRINGS, "No", "Yes", 0, PANEL_VALUE, show_colorbar, PANEL_NOTIFY_PROC, panel_set_item, 0); pan_set_marker = panel_create_item (setup_panel, PANEL_CYCLE, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(10) + 8, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Cursor marker: ", PANEL_CHOICE_STRINGS, "None", "Circle", "Cross", "Square", 0, PANEL_VALUE, marktype, PANEL_NOTIFY_PROC, panel_set_item, 0); pan_blink_rate = panel_create_item (setup_panel, PANEL_CYCLE, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(11) + 8, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Blink rate (sec): ", PANEL_CHOICE_STRINGS, BLINKRATE_CHOICES, 0, PANEL_VALUE, blink_rate_index, PANEL_NOTIFY_PROC, panel_set_item, 0); pan_blink_list = panel_create_item (setup_panel, PANEL_TEXT, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(12) + 11, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Frames to be blinked: ", PANEL_VALUE, s_blinklist, PANEL_VALUE_STORED_LENGTH, SZ_FNAME, PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, PANEL_NOTIFY_PROC, set_blinklist, 0); pan_zoom_list = panel_create_item (setup_panel, PANEL_TEXT, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(13) + 11, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Zoom factors: ", PANEL_VALUE, s_zoomslist, PANEL_VALUE_STORED_LENGTH, SZ_FNAME, PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, PANEL_NOTIFY_PROC, set_zoomslist, 0); strcpy (o_fname, COORDFILE); pan_set_ofname = panel_create_item (setup_panel, PANEL_TEXT, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(14) + 11, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Coordinate list output file: ", PANEL_VALUE, o_fname, PANEL_VALUE_STORED_LENGTH, SZ_FNAME, PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, PANEL_NOTIFY_PROC, set_ofname, 0); pan_set_rfname = panel_create_item (setup_panel, PANEL_TEXT, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(15) + 11, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Rasterfile name (load/save): ", PANEL_VALUE, rasterfile, PANEL_VALUE_STORED_LENGTH, SZ_FNAME, PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, PANEL_NOTIFY_PROC, set_rfname, 0); pan_set_rtype = panel_create_item (setup_panel, PANEL_CYCLE, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(16) + 13, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Screendump output type: ", PANEL_CHOICE_STRINGS, "postscript", "rasterfile", 0, PANEL_VALUE, r_type, PANEL_NOTIFY_PROC, panel_set_item, 0); pan_set_rdispose = panel_create_item (setup_panel, PANEL_TEXT, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(17) + 13, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Screendump dispose command: ", PANEL_VALUE, r_dispose, PANEL_VALUE_STORED_LENGTH, SZ_FNAME, PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, PANEL_NOTIFY_PROC, set_rdispose, 0); pan_set_rfilename = panel_create_item (setup_panel, PANEL_TEXT, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(18) + 11, PANEL_DISPLAY_LEVEL, PANEL_CURRENT, PANEL_LABEL_STRING, "Screendump output file: ", PANEL_VALUE, r_filename, PANEL_VALUE_STORED_LENGTH, SZ_FNAME, PANEL_VALUE_DISPLAY_LENGTH, SZ_PANTEXT, PANEL_NOTIFY_PROC, set_rfilename, 0); panel_create_item (setup_panel, PANEL_BUTTON, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(19) + 15, PANEL_LABEL_IMAGE, panel_button_image (setup_panel,"Register Frames",0,0), PANEL_NOTIFY_PROC, register_proc, 0); panel_create_item (setup_panel, PANEL_BUTTON, PANEL_LABEL_IMAGE, panel_button_image (setup_panel, "Fit Window", 0,0), PANEL_NOTIFY_PROC, fitframe_proc, 0); panel_create_item (setup_panel, PANEL_BUTTON, PANEL_LABEL_IMAGE, panel_button_image (setup_panel, "Blink", 0,0), PANEL_NOTIFY_PROC, blinkenable_proc, 0); panel_create_item (setup_panel, PANEL_BUTTON, PANEL_LABEL_IMAGE, panel_button_image (setup_panel, "Frame", 0,0), PANEL_NOTIFY_PROC, setframe_proc, 0); panel_create_item (setup_panel, PANEL_BUTTON, PANEL_ITEM_X, ATTR_COL(0), PANEL_ITEM_Y, ATTR_ROW(20) + 15, PANEL_LABEL_IMAGE, panel_button_image (setup_panel, "Reset", 0,0), PANEL_NOTIFY_PROC, reset_proc, 0); panel_create_item (setup_panel, PANEL_BUTTON, PANEL_LABEL_IMAGE, panel_button_image (setup_panel, "Iclear", 0,0), PANEL_NOTIFY_PROC, iclear_proc, 0); panel_create_item (setup_panel, PANEL_BUTTON, PANEL_LABEL_IMAGE, panel_button_image (setup_panel, "Gclear", 0,0), PANEL_NOTIFY_PROC, gclear_proc, 0); panel_create_item (setup_panel, PANEL_BUTTON, PANEL_LABEL_IMAGE, panel_button_image (setup_panel, "Load", 0,0), PANEL_NOTIFY_PROC, loadframe_proc, 0); panel_create_item (setup_panel, PANEL_BUTTON, PANEL_LABEL_IMAGE, panel_button_image (setup_panel, "Save", 0,0), PANEL_NOTIFY_PROC, saveframe_proc, 0); panel_create_item (setup_panel, PANEL_BUTTON, PANEL_LABEL_IMAGE, panel_button_image (setup_panel, "DISMISS", 0,0), PANEL_NOTIFY_PROC, setup_proc, 0); window_fit (setup_panel); window_fit (setup_frame); } /* PANEL_SET_ITEM -- Called when an item is seleted in the setup panel to * set the associated global variable and possibly take some action. */ static panel_set_item (item, value) Panel_item item; int value; { if (item == pan_set_nframes) { set_fbconfig (fb_config_index, value + 1); } else if (item == pan_set_maptype) { df_p->fb_maptype = maptype = value; set_colortable(); set_transfer_function (gio_pw, df_p->fb_center, df_p->fb_slope); } else if (item == pan_crandom_rate) { crandom_blink_rate = value; } else if (item == pan_set_marker) { marktype = value; } else if (item == pan_blink_rate) { blink_rate_index = value; } else if (item == pan_set_rtype) { r_type = value; } else if (item == pan_globalcolor) { global_colortable = value; } else if (item == pan_set_background) { /* Set the background color. */ if (fb_bkgcolor_index != value) { register unsigned char *fb, *op; register int n = Fb_height * Fb_width; fb = (unsigned char *) mpr_d(df_p->fb_pr)->md_image; switch (fb_bkgcolor_index = value) { case BKG_BLACK: background = CMS_BACKGROUND; for (op=fb; --n >= 0; op++) if (!*op) *op = background; break; case BKG_WHITE: background = 0; for (op=fb; --n >= 0; op++) if (*op == CMS_BACKGROUND) *op = 0; break; } gclear_proc(); } } else if (item == pan_show_colorbar) { if (show_colorbar != value) { struct pixrect *pr = get_screen_rect(); show_colorbar = value; if (show_colorbar) { cb_height = SZ_COLORBAR; gio_ysize += cb_height; gio_ysize = min (Fb_height + cb_height, gio_ysize); } else { cb_height = 0; gio_ysize -= SZ_COLORBAR; } gio_xsize = min (pr->pr_width - TOOL_BORDERWIDTH * 2, gio_xsize); gio_ysize = min (pr->pr_height - tool_headerheight ((int) window_get (gio_frame, FRAME_SHOW_LABEL)) - TOOL_BORDERWIDTH, gio_ysize); window_set (gio_canvas, WIN_WIDTH,gio_xsize, WIN_HEIGHT,gio_ysize, 0); window_fit (gio_canvas); window_fit (gio_frame); } } else if (item == pan_snapframetoo) snap_frame_too = value; } /* SET_ZOOMSLIST -- Set the list of zoom factors. */ static Panel_setting set_zoomslist (item, event) Panel_item item; Event *event; { register char *ip; register int i; strcpy (s_zoomslist, (char *) panel_get_value (item)); for (ip=s_zoomslist; isspace (*ip); ip++) ; nzooms = 0; while (*ip && isdigit (*ip)) { zooms[nzooms++] = max (1, atoi(ip)); while (isdigit (*ip)) ip++; while (isspace (*ip)) ip++; if (nzooms >= MAX_ZOOMS) break; } return (panel_text_notify (item,event)); } /* SET_BLINKLIST -- Set the list of frames to be blinked. */ static Panel_setting set_blinklist (item, event) Panel_item item; Event *event; { register char *ip; register int i; strcpy (s_blinklist, (char *) panel_get_value (item)); for (ip=s_blinklist; isspace (*ip); ip++) ; n_blink_frames = 0; if (strncmp (ip, "all", 3) == 0) { n_blink_frames = MAX_FRAMES; for (i=0; i < MAX_FRAMES; i++) blink_frames[i] = i + 1; } else { while (*ip && isdigit (*ip)) { blink_frames[n_blink_frames++] = atoi(ip); while (isdigit (*ip)) ip++; while (isspace (*ip)) ip++; } } return (panel_text_notify (item,event)); } /* BLINKENABLE_PROC -- Turn frame blink on or off. */ static blinkenable_proc() { blink = !blink; menu_set (blink_item, MENU_STRING, blink ? "Blink off" : "Blink on", 0); blink_frame = n_blink_frames - 1; blink_timer = 0; } /* REGISTER_PROC -- Register all frames with the current frame. */ static register_proc() { register struct framebuf *fr_p; register int i; for (i=0, fr_p=frames; i < fb_nframes; i++, fr_p++) if (fr_p != df_p) set_zoom (fr_p, df_p->fb_xoff, df_p->fb_yoff, df_p->fb_xzoom); } /* SET_OFNAME -- Set the file name for coordinate output. */ static Panel_setting set_ofname (item, event) Panel_item item; Event *event; { char *s; s = (char *) panel_get_value (item); if (strcmp (s, o_fname)) { strcpy (o_fname, s); df_p->fb_imageno = 0; df_p->fb_objno = 1; window_set (gio_frame, FRAME_LABEL, framelabel(), 0); } return (panel_text_notify (item,event)); } /* SET_ULUT1 -- Set the file name for user lookup table 1. */ static Panel_setting set_ulut1 (item, event) Panel_item item; Event *event; { char *s; strcpy (u_lut1, (char *) panel_get_value (item)); return (panel_text_notify (item,event)); } /* SET_ULUT2 -- Set the file name for user lookup table 2. */ static Panel_setting set_ulut2 (item, event) Panel_item item; Event *event; { char *s; strcpy (u_lut2, (char *) panel_get_value (item)); return (panel_text_notify (item,event)); } /* SET_RFNAME -- Set the file name for rasterfile load/save. */ static Panel_setting set_rfname (item, event) Panel_item item; Event *event; { char *s; strcpy (rasterfile, (char *) panel_get_value (item)); return (panel_text_notify (item,event)); } /* SET_RDISPOSE -- Set the raster file dispose command. */ static Panel_setting set_rdispose (item, event) Panel_item item; Event *event; { char *s; strcpy (r_dispose, (char *) panel_get_value (item)); return (panel_text_notify (item,event)); } /* SET_RFILENAME -- Set the screendump filename template. */ static Panel_setting set_rfilename (item, event) Panel_item item; Event *event; { char *s; strcpy (r_filename, (char *) panel_get_value (item)); return (panel_text_notify (item,event)); } /* LOADFRAME_PROC -- Load the named rasterfile into the current frame. */ static loadframe_proc() { char fname[SZ_FNAME+1]; char buf[SZ_FNAME+1]; sprintf (buf, rasterfile, df_p->fb_frameno, df_p->fb_imageno); strcpy (fname, getfname(buf, 0)); load_raster (df_p->fb_pr, fname); } /* SAVEFRAME_PROC -- Save the current frame in the named rasterfile. */ static saveframe_proc() { char fname[SZ_FNAME+1]; char buf[SZ_FNAME+1]; sprintf (buf, rasterfile, df_p->fb_frameno, df_p->fb_imageno); strcpy (fname, getfname(buf, 0)); save_raster (df_p->fb_pr, fname); } /* FITFRAME_PROC -- Fit the display window to the current frame buffer size. */ static fitframe_proc() { register struct pixrect *pr = get_screen_rect(); gio_xsize = min (pr->pr_width - TOOL_BORDERWIDTH * 2, Fb_width); gio_ysize = min (pr->pr_height - tool_headerheight ((int)window_get(gio_frame,FRAME_SHOW_LABEL)) - TOOL_BORDERWIDTH, Fb_height + cb_height); window_set (gio_canvas, WIN_WIDTH, gio_xsize, WIN_HEIGHT, gio_ysize, 0); window_fit (gio_canvas); window_fit (gio_frame); } /* GET_SCREEN_RECT -- Determine the size of the workstation screen. */ static struct pixrect * get_screen_rect() { static struct pixrect screen; struct pixrect *pr; if (!screen.pr_width) if (pr = pr_open ("/dev/fb")) { screen = *pr; pr_close (pr); } else { screen.pr_width = 1152; screen.pr_width = 900; } return (&screen); } /* SETUP_PROC -- Toggle whether or not the setup panel is shown. */ static setup_proc() { if ((int) window_get (setup_frame, WIN_SHOW) == TRUE) { setup_xoff = (int) window_get (setup_frame, WIN_X, 0); setup_yoff = (int) window_get (setup_frame, WIN_Y, 0); window_set (setup_frame, WIN_SHOW, FALSE, 0); } else { window_set (setup_frame, WIN_X, setup_xoff, WIN_Y, setup_yoff, 0); window_set (setup_frame, WIN_SHOW, TRUE, 0); } } /* CREATE_FRAME_MENU -- Imtool uses a special frame menu which provides the * standard frame menu as a submenu. */ static create_frame_menu (frame) Frame frame; { extern imagecopy_proc(), register_proc(); extern setup_proc(), setframe_proc(), fitframe_proc(); extern iclear_proc(), gclear_proc(), blinkenable_proc(); Menu new_menu, old_menu; /* Get the standard frame menu. */ old_menu = (Menu) window_get (frame, WIN_MENU); /* Create the new frame root menu */ new_menu = menu_create ( MENU_PULLRIGHT_ITEM, "Frame", old_menu, MENU_ACTION_ITEM, "Setup", setup_proc, MENU_ACTION_ITEM, "Register", register_proc, MENU_ACTION_ITEM, "Blink on", blinkenable_proc, MENU_ACTION_ITEM, "FitFrame", fitframe_proc, MENU_ACTION_ITEM, "NextFrame", setframe_proc, MENU_ACTION_ITEM, "Gclear", gclear_proc, MENU_ACTION_ITEM, "Iclear", iclear_proc, MENU_ACTION_ITEM, "Imcopy", imagecopy_proc, 0); blink_item = menu_find (new_menu, MENU_STRING, "Blink on", 0); /* Install the new menu. */ window_set (frame, WIN_MENU, new_menu, 0); } /* INIT_FRAMEBUFFERS -- Allocate space for the indicated number and size of * framebuffers, initializing the framebuffer data structures accordingly. * If at least one frame buffer of the desired size can be allocated we * consider it a success, but set fb_nframes accordingly. -1 is returned * if no frames of the desired size can be allocated. */ static init_framebuffers (config, nframes) int config; /* new frame buffer configuration */ int nframes; /* desired number of frames */ { register struct framebuf *fb; register int i; char *calloc(); nframes = min (MAX_FRAMES, nframes); /* If we are only changing the number of frames in the current * configuration, keep the old frames. */ if (frames && config == fb_config_index) { if (nframes == fb_config[config].nframes) { fb_nframes = nframes; return (nframes); } else if (nframes < fb_config[config].nframes) { for (i=nframes; i < fb_nframes; i++) pr_close (frames[i].fb_pr); fb_config[config].nframes = fb_nframes = nframes; if (reference_frame > nframes) { reference_frame = nframes; rf_p = frames + (reference_frame - 1); } if (display_frame > nframes) set_frame (nframes); return (nframes); } else if (nframes > fb_config[config].nframes) ; /* fall through and add more frames */ } else { /* Deallocate old frame buffers, if any. */ if (frames) { pr_close (cb_pr); for (i=0; i < fb_nframes; i++) pr_close (frames[i].fb_pr); free (frames); } fb_nframes = 0; frames = (struct framebuf *) calloc (MAX_FRAMES, sizeof(struct framebuf)); df_p = rf_p = frames; display_frame = reference_frame = 1; strcpy (o_fname, COORDFILE); wc_xoff = wc_yoff = 0; } /* Allocate and initialize the new frame buffers. */ fb_config_index = config; Fb_width = fb_config[config].width; Fb_height = fb_config[config].height; for (i=fb_nframes; i < nframes; i++) { fb = frames + i; fb->fb_pr = mem_create (Fb_width, Fb_height, fb_depth); if (fb->fb_pr == NULL) { fprintf (stderr, "attempt to allocate frame buffer %d (%dx%d) fails\n", i + 1, Fb_width, Fb_height); if (i) break; else return (-1); } else if (!fb_nframes++) { cb_pr = mem_create (Fb_width, cb_height, fb_depth); if (pw_rect.r_width) init_colorbar (pw_rect.r_width); } fb->fb_xoff = 0; fb->fb_yoff = 0; fb->fb_xzoom = fb->fb_yzoom = 1; fb->fb_center = fb_ngrey / 2.0; fb->fb_slope = (float)white / (float)(fb_ngrey - 1); fb->fb_maptype = maptype; fb->fb_objno = 1; fb->fb_imageno = 0; fb->fb_frameno = i + 1; fb->fb_ctran.valid = 0; fb->fb_ctran.imtitle[0] = '\0'; strcpy (fb->fb_ctran.format, W_DEFFORMAT); } set_zoom (df_p, 0, 0, 1); return (fb_config[config].nframes = fb_nframes); } /* INIT_COLORBAR -- Write the colorbar into the frame buffer. The length of * the colorbar should correspond to the current width of the display window, * but must not exceed the width of the frame buffer. */ init_colorbar (cb_width) int cb_width; { register int i; unsigned char *lp; Pixrect *pr; if (cb_height <= 0) return; if ((pr = mem_create (cb_width, 1, fb_depth)) != NULL) { lp = (unsigned char *) mpr_d(pr)->md_image; /* Write colorbar. */ for (i=0; i < cb_width; i++) lp[i] = (CMS_DATARANGE-1) * i / (cb_width-1) + CMS_DATASTART; for (i=3; i < cb_height; i++) pr_rop (cb_pr, 0, i, cb_width, 1, PIX_SRC, pr, 0, 0); /* Add a border between image and colorbar. */ for (i=0; i < cb_width; i++) lp[i] = NGREY-1; for (i=0; i < 3; i++) pr_rop (cb_pr, 0, i, cb_width, 1, PIX_SRC, pr, 0, 0); for (i=0; i < cb_width; i++) lp[i] = 0; for (i=1; i < 2; i++) pr_rop (cb_pr, 0, i, cb_width, 1, PIX_SRC, pr, 0, 0); pr_close (pr); } } /* INIT_COLORMAP -- Initialize the IMTOOL color map. */ static init_colormap (pw) struct pixwin *pw; { register unsigned char *r = red; register unsigned char *g = green; register unsigned char *b = blue; int planes = NGREY-1, i; /* Initialize the IMTOOL colormap from the current fullscreen * colormap, so that the (small) colormap entries of the other * windows will be preserved, as far as possible. */ grab_colormap (r, g, b); /* Set a linear transfer function for the main part of the table. */ for (i=CMS_DATASTART; i <= CMS_DATAEND; i++) r[i] = g[i] = b[i] = i * (white + 1) / CMS_DATARANGE; /* Color table entry for the cursor. */ r[CMS_CURSOR] = white; g[CMS_CURSOR] = white; b[CMS_CURSOR] = white; /* Set the background and graphics colors. */ i = CMS_BACKGROUND; r[i] = 0; g[i] = 0; b[i] = 0; i++; /* 202=black */ i = CMS_GRAPHICSSTART; r[i] = 255; g[i] = 255; b[i] = 255; i++; /* 203=white */ r[i] = 255; g[i] = 0; b[i] = 0; i++; /* 204=red */ r[i] = 0; g[i] = 255; b[i] = 0; i++; /* 205=green */ r[i] = 0; g[i] = 0; b[i] = 255; i++; /* 206=blue */ r[i] = 255; g[i] = 255; b[i] = 0; i++; /* 207=yellow */ r[i] = 0; g[i] = 255; b[i] = 255; i++; /* 208=cyan */ r[i] = 255; g[i] = 0; b[i] = 255; i++; /* 209=magenta */ r[i] = 255; g[i] = 127; b[i] = 0; i++; /* 210=coral */ r[i] = 142; g[i] = 35; b[i] = 107; i++; /* 211=maroon */ r[i] = 204; g[i] = 50; b[i] = 50; i++; /* 212=orange */ r[i] = 159; g[i] = 159; b[i] = 95; i++; /* 213=khaki */ r[i] = 219; g[i] = 112; b[i] = 219; i++; /* 214=orchid */ r[i] = 112; g[i] = 219; b[i] = 219; i++; /* 215=turquoise */ r[i] = 159; g[i] = 95; b[i] = 159; i++; /* 216=violet */ r[i] = 216; g[i] = 216; b[i] = 191; i++; /* 217=wheat */ pw_setcmsname (pw, CMMAPNAME); pw_putcolormap (pw, 0, NGREY, r, g, b); pw_putattributes (pw, &planes); } /* COMPUTE_TRANSFER_FUNCTION -- Compute the slope and offset of the transfer * function for the current display frame, given the coordinates of the * mouse in the frame. */ static compute_transfer_function (event) Event *event; { float xsize, ysize; float y, slope; int neg; xsize = pw_rect.r_width; ysize = pw_rect.r_height; /* Compute the slope of the transfer function. */ y = event_y(event) / ysize * 2.0 - 1.0; if (neg = (y < 0.0)) y = -y; if (y > 0.99) y = 0.99; if ((slope = tan (y * M_PI_2)) > white) slope = white; /* Record new transfer function in frame buffer descriptor. */ df_p->fb_center = event_x(event) / xsize * (fb_ngrey-1); df_p->fb_slope = neg ? -slope : slope; } /* SET_TRANSFER_FUNCTION -- Load the color map as necessary to implement the * given linear transfer function. */ static set_transfer_function (pw, center, slope) struct pixwin *pw; /* reference pixwin */ float center; /* greyscale value at half intensity */ float slope; /* delta-intensity per greyscale unit */ { register int i; register float z, zmin, zmax; unsigned char o_red[NGREY], o_green[NGREY], o_blue[NGREY]; unsigned char *p_r, *p_g, *p_b; if (center < CMS_DATASTART) center = CMS_DATASTART; else if (center > CMS_DATAEND) center = CMS_DATAEND; zmin = 0.0; zmax = white; z = white / 2; for (i=center; i <= CMS_DATAEND; i++) { o_red[i] = m_red[(unsigned char)(int)z]; o_green[i] = m_green[(unsigned char)(int)z]; o_blue[i] = m_blue[(unsigned char)(int)z]; z += slope; if (z <= zmin) z = zmin; else if (z >= zmax) z = zmax; } z = white / 2; for (i=center; i >= CMS_DATASTART; i--) { o_red[i] = m_red[(unsigned char)(int)z]; o_green[i] = m_green[(unsigned char)(int)z]; o_blue[i] = m_blue[(unsigned char)(int)z]; z -= slope; if (z <= zmin) z = zmin; else if (z >= zmax) z = zmax; } p_r = &o_red[CMS_DATASTART]; p_g = &o_green[CMS_DATASTART]; p_b = &o_blue[CMS_DATASTART]; /*pw_putcolormap (pw, CMS_DATASTART, CMS_DATARANGE, p_r, p_g, p_b);*/ bcopy (p_r, &red[CMS_DATASTART], CMS_DATARANGE); bcopy (p_g, &green[CMS_DATASTART], CMS_DATARANGE); bcopy (p_b, &blue[CMS_DATASTART], CMS_DATARANGE); /* Reset the full 8 bit colormap for the pixwin, to pick up any * changes made in the unused regions for other windows, picked up * by edit_colortable below. */ pw_putcolormap (pw, 0, NGREY, red, green, blue); } /* SET_COLORTABLE -- Set up the RGB lookup tables used to map the windowed * monochrome output of a frame buffer into the hardware colormap. */ static Notify_value set_colortable() { register int v, vsat, step, i; static int seed = 0; int knot[7]; vsat = NGREY - 1; step = NGREY / 6; for (i=0; i < 7; i++) knot[i] = i * step; knot[6] = vsat; switch (df_p->fb_maptype) { case MONO: for (i=0; i < NGREY; i++) m_red[i] = m_green[i] = m_blue[i] = i; break; case HEAT: for (i=0; i < NGREY; i++) { m_red[i] = heat.hue[i].red * (NGREY - 1); m_green[i] = heat.hue[i].green * (NGREY - 1); m_blue[i] = heat.hue[i].blue * (NGREY - 1); } break; case RAMP1: for (i=0; i < NGREY; i++) { m_red[i] = heat.hue[i].red * NGREY; m_green[i] = heat.hue[i].green * NGREY; m_blue[i] = heat.hue[i].blue * NGREY; } break; case RAMP2: for (i=0; i < NGREY; i++) { m_red[i] = heat.hue[i].red * ((NGREY - 1) * 2); m_green[i] = heat.hue[i].green * ((NGREY - 1) * 2); m_blue[i] = heat.hue[i].blue * ((NGREY - 1) * 2); } break; case HALLEY: for (i=0; i < NGREY; i++) { m_red[i] = halley.hue[i].red * (NGREY - 1); m_green[i] = halley.hue[i].green * (NGREY - 1); m_blue[i] = halley.hue[i].blue * (NGREY - 1); } break; case ULUT1: case ULUT2: { struct lut user; struct triplet *p; int i, j; FILE *fp; char *s; s = (df_p->fb_maptype == ULUT1) ? u_lut1 : u_lut2; if ((fp = fopen (getfname(s,0), "r")) == NULL) { fprintf (stderr, "cannot open %s\n", s); return; } for (user.lutlen=0; user.lutlen < NGREY; user.lutlen++) { p = &user.hue[user.lutlen]; if (fscanf (fp, " %f %f %f", &p->red, &p->green, &p->blue) == EOF) break; } for (i=0; i < NGREY; i++) { j = max(0, min(NGREY-1, (i * user.lutlen / NGREY))); m_red[i] = user.hue[j].red * (NGREY - 1); m_green[i] = user.hue[j].green * (NGREY - 1); m_blue[i] = user.hue[j].blue * (NGREY - 1); } fclose (fp); } break; case LINEARPS: for (i=0; i < NGREY; i++) m_red[i] = m_green[i] = m_blue[i] = 0; for (i=knot[0]; i <= knot[1]; i++) m_blue[i] = vsat * (i - knot[0]) / step; for (i=knot[1]; i <= knot[2]; i++) m_blue[i] = vsat; for (i=knot[2]; i <= knot[3]; i++) m_blue[i] = vsat * (knot[3] - i) / step; for (i=knot[1]; i <= knot[2]; i++) m_green[i] = vsat * (i - knot[1]) / step; for (i=knot[2]; i <= knot[4]; i++) m_green[i] = vsat; for (i=knot[4]; i <= knot[5]; i++) m_green[i] = vsat * (knot[5] - i) / step; for (i=knot[3]; i <= knot[4]; i++) m_red[i] = vsat * (i - knot[3]) / step; for (i=knot[4]; i <= knot[6]; i++) m_red[i] = vsat; for (i=knot[5]; i <= knot[6]; i++) { if ((v = vsat * (i - knot[5]) / step) > vsat) v = vsat; m_green[i] = m_blue[i] = v; } break; case CRANDOMPS: set_transfer_function (gio_pw, df_p->fb_center, df_p->fb_slope); imt_pause (cr_msec[crandom_blink_rate], set_colortable); /* fall through */ case RANDOMPS: if (!seed) seed = time(0); srand (seed++); for (i=0; i < NGREY; i++) { m_red[i] = ((rand() >> 4) % NGREY); m_green[i] = ((rand() >> 4) % NGREY); m_blue[i] = ((rand() >> 4) % NGREY); } break; } } /* GRAB_COLORMAP -- Read the current physical full screen colormap. */ static grab_colormap (red, green, blue) unsigned char red[], green[], blue[]; { struct pixrect *screen; if (window_open) { screen = pr_open ("/dev/fb"); pr_getcolormap (screen, 0, NGREY, red, green, blue); pr_close (screen); } } /* IMTOOL_CLOCK -- The main imtool clock. */ static imtool_clock (client, event, arg) Notify_client client; Notify_event event; Notify_arg arg; { static int delay=0, interval=0, toggle=0; Cursor cursor; int frame, n; /* Blink cursor (variable rate). */ cursor = window_get (gio_canvas, WIN_CURSOR); toggle = !toggle; if (reading_imcursor) { cursor_set (cursor, CURSOR_OP, toggle ? PIX_NOT(PIX_SRC) & PIX_DST : PIX_SRC | PIX_DST | PIX_COLOR(NGREY-1), 0); } else { cursor_set (cursor, CURSOR_CROSSHAIR_COLOR, toggle ? CMS_BACKGROUND : CMS_CURSOR, 0); } window_set (gio_canvas, WIN_CURSOR, cursor, 0); /* Things that happen at a fixed interval. */ if ((delay += interval) >= CLOCK_INTERVAL) { /* Keep imtool visible (if window open). */ edit_colormap(); /* Frame blink. The frames in the blink frame list do not have to * exist; if not, then advance through the list until either a valid * frame is found, or the list has been traversed once. */ if (blink && n_blink_frames > 0 && state != WINDOW && window_open) { if (--blink_timer <= 0) { for (n=n_blink_frames; --n >= 0; ) { if (++blink_frame >= n_blink_frames) blink_frame = 0; frame = blink_frames[blink_frame]; if (frame >= 1 && frame <= fb_nframes) { set_frame (frame); if (display_coords && state == TRACK_CURSOR) update_coords (NULL); break; } } blink_timer = blink_rate[blink_rate_index]; } } delay = 0; } interval = reading_imcursor ? CLOCK_INTERVAL/4 : CLOCK_INTERVAL; imt_pause (interval, imtool_clock); } /* EDIT_COLORMAP -- Overwrite the portion of the full screen colormap used * by the display server. This must be done in such a way that changes to * the region of the screen colortable used by other windows are preserved. */ static edit_colormap() { struct pixrect *screen; unsigned char r[NGREY], g[NGREY], b[NGREY]; if (state != WINDOW && window_open) { /* Edit the physical colortable. */ screen = pr_open ("/dev/fb"); pr_getcolormap (screen, 0, NGREY, r, g, b); /* Make the cursor blink between black and white for better vis. * (>> now done with set_cursor in imtool_clock()) if (green[CMS_CURSOR] == white) { red[CMS_CURSOR] = black; green[CMS_CURSOR] = black; blue[CMS_CURSOR] = black; } else { red[CMS_CURSOR] = white; green[CMS_CURSOR] = white; blue[CMS_CURSOR] = white; } */ bcopy (&red[CMS_FIRST], &r[CMS_FIRST], CMS_NGREY); bcopy (&green[CMS_FIRST], &g[CMS_FIRST], CMS_NGREY); bcopy (&blue[CMS_FIRST], &b[CMS_FIRST], CMS_NGREY); pw_putcolormap (gio_pw, 0, NGREY, r, g, b); if (global_colortable) pr_putcolormap (screen, 0, NGREY, r, g, b); pr_close (screen); /* Update the canvas pixwin colortable. */ bcopy (r, red, NGREY); bcopy (g, green, NGREY); bcopy (b, blue, NGREY); } } /* SHOW_COLORMAP -- Print the contents of the color map for a pixwin. */ static show_colormap (pw, first, last) struct pixwin *pw; int first, last; { unsigned char r[NGREY], g[NGREY], b[NGREY]; char cmsname[CMS_NAMESIZE]; int i, n; pw_getcmsname (pw, cmsname); pw_getcolormap (pw, 0, NGREY, r, g, b); printf ("color map segment = '%s'\n", cmsname); for (i=first, n=0; i <= last; i++) { printf ("%3d %3d %3d", r[i], g[i], b[i]); printf ((++n % 5) ? " " : "\n"); } printf ("\n"); } /* LOAD_TESTPATTERN -- Load a test pattern into the reference frame buffer. */ static load_testpattern (type) int type; /* pattern type desired */ { register unsigned char *line; register int i, j, color; unsigned char *fb, *oline; fb = (unsigned char *) mpr_d(df_p->fb_pr)->md_image; switch (type) { case 0: /* Compute first line. */ oline = line = fb; for (i=0, color=0; i < Fb_width; i++) if (((i+16) % 32) == 0) { line[i] = 0; color = ((i+j) % CMS_DATARANGE) / 32 * 32; } else line[i] = color; /* Compute remaining lines. */ for (j=1; j < Fb_height; j++) { line = fb + j * Fb_width; if (((j+16) % 32) == 0) { for (i=0; i < Fb_width; i++) line[i] = 0; if (++j >= Fb_height) break; line = fb + j * Fb_width; color = (j % CMS_DATARANGE) / 32 * 32; for (i=0; i < Fb_width; i++) if (((i+16) % 32) == 0) { line[i] = 0; color = ((i+j) % CMS_DATARANGE) / 32 * 32; } else line[i] = color; oline = line; } else bcopy (oline, line, Fb_width); } break; case 1: for (j=1; j < Fb_height; j++) { line = fb + j * Fb_width; for (i=0; i < Fb_width; i++) line[i] = (i % CMS_DATARANGE); } break; case 2: for (j=1; j < Fb_height; j++) { line = fb + j * Fb_width; for (i=0; i < Fb_width; i++) line[i] = ((i+j) % CMS_DATARANGE); } break; } } /* For the moment we take an IIS model 70 command/data stream as input; this * is used to load images into the image display. This is a kludge interface * for the prototype, convenient since the high level software is written for * the IIS. */ #define MEMORY 01 /* frame buffer i/o */ #define LUT 02 /* lut i/o */ #define FEEDBACK 05 /* used for frame clears */ #define IMCURSOR 020 /* logical image cursor */ #define WCS 021 /* used to set WCS */ #define SZ_IMCURVAL 160 #define PACKED 0040000 #define COMMAND 0100000 #define IIS_READ 0100000 #define IMC_SAMPLE 0040000 #define IMT_FBCONFIG 077 #define XYMASK 077777 struct iism70 { short tid; short thingct; short subunit; short checksum; short x, y, z; short t; }; /* EV_CMDINPUT -- Called when command or data input has arrived via the * pseudodevice input stream from some applications process. */ static Notify_value ev_cmdinput (frame, event, arg, type) Frame frame; Event *event; Notify_arg arg; Notify_event_type type; { register unsigned char *cp; register int sum, i; register short *p; int ndatabytes, nbytes, n, ntrys=0; static int errmsg=0, bswap=0; struct iism70 iis; char buf[SZ_FIFOBUF]; int fb_index; /* Get the IIS header. */ if (read (datain, (char *)&iis, sizeof(iis)) < sizeof(iis)) { fprintf (stderr, "imtool: command input read error\n"); return (NOTIFY_DONE); } else if (bswap) bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); /* Verify the checksum. If it fails swap the bytes and try again. */ for (;;) { for (i=0, sum=0, p=(short *)&iis; i < 8; i++) sum += *p++; if ((sum & 0177777) == 0177777) break; if (ntrys++) { if (!errmsg++) { fprintf (stderr, "imtool: bad data header checksum\n"); if (bswap) bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); fprintf (stderr, "noswap:"); for (i=0, p=(short *)&iis; i < 8; i++) fprintf (stderr, " %6o", p[i]); fprintf (stderr, "\n"); bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); fprintf (stderr, " swap:"); for (i=0, p=(short *)&iis; i < 8; i++) fprintf (stderr, " %6o", p[i]); fprintf (stderr, "\n"); } break; } else { bswap2 ((char *)&iis, (char *)&iis, sizeof(iis)); bswap = !bswap; } } ndatabytes = -iis.thingct; if (!(iis.tid & PACKED)) ndatabytes *= 2; switch (iis.subunit & 077) { case FEEDBACK: /* The feedback unit is used only to clear a frame. */ set_reference_frame (decode_frameno (iis.z & 07777)); erase (rf_p); break; case LUT: /* Data mode writes to the frame lookup tables are not implemented. * A command mode write to the LUT subunit is used to connect * image memories up to the RGB channels, i.e., to select the frame * to be displayed. We ignore any attempt to assign multiple * frames to multiple color channels, and just do a simple frame * select. */ if (iis.subunit & COMMAND) { int frame, z, n; short x[14]; if (read (datain, (char *)x, ndatabytes) == ndatabytes) { if (bswap) bswap2 ((char *)x, (char *)x, ndatabytes); z = x[0]; if (!z) z = 1; for (n=0; !(z & 1); z >>= 1) n++; frame = max (1, n + 1); if (frame > fb_nframes) { if (frame < MAX_FRAMES) set_fbconfig (fb_config_index, frame); else { fprintf (stderr, "imtool warning: "); fprintf (stderr, "attempt to display nonexistent frame %d\n", frame); frame = fb_nframes - 1; } } set_frame (frame); return (NOTIFY_DONE); } } case MEMORY: /* Load data into the frame buffer. Data is assumed to be byte * packed. */ if (iis.tid & IIS_READ) { /* Read from the display. */ unsigned char *fb, *ip; int nbytes, nleft, n, x, y; long starttime; /* Get the frame to be read from. */ set_reference_frame (decode_frameno (iis.z & 07777)); fb = (unsigned char *) mpr_d(rf_p->fb_pr)->md_image; nbytes = ndatabytes; x = iis.x & XYMASK; y = iis.y & XYMASK; ip = max (fb, min (fb + Fb_width * Fb_height - nbytes, fb + y * Fb_width + x)); if (ip != fb + y * Fb_width + x) { fprintf (stderr, "imtool: attempted read out of bounds on framebuf\n"); fprintf (stderr, "read %d bytes at [%d,%d]\n", nbytes, x, y); } /* Return the data from the frame buffer. */ starttime = time(0); for (nleft = nbytes; nleft > 0; nleft -= n) { n = (nleft < SZ_FIFOBUF) ? nleft : SZ_FIFOBUF; if ((n = write (dataout, ip, n)) <= 0) { if (n < 0 || (time(0) - starttime > IO_TIMEOUT)) { fprintf (stderr, "IMTOOL: timeout on write\n"); break; } } else ip += n; } return (NOTIFY_DONE); } else { /* Write to the display. */ unsigned char *fb, *op; int nbytes, nleft, n, x, y; long starttime; /* Get the frame to be written into (encoded with a bit for * each frame, 01 is frame 1, 02 is frame 2, 04 is frame 3, * and so on). */ set_reference_frame (decode_frameno (iis.z & 07777)); /* Get a pointer into the frame buffer where the data will * be put. */ fb = (unsigned char *) mpr_d(rf_p->fb_pr)->md_image; nbytes = ndatabytes; x = iis.x & XYMASK; y = iis.y & XYMASK; op = max (fb, min (fb + Fb_width * Fb_height - nbytes, fb + y * Fb_width + x)); if (op != fb + y * Fb_width + x) { fprintf (stderr, "imtool: attempted write out of bounds on framebuf\n"); fprintf (stderr, "write %d bytes to [%d,%d]\n", nbytes, x, y); } /* Read the data into the frame buffer. */ starttime = time(0); for (nleft = nbytes; nleft > 0; nleft -= n) { n = (nleft < SZ_FIFOBUF) ? nleft : SZ_FIFOBUF; if ((n = read (datain, op, n)) <= 0) { if (n < 0 || (time(0) - starttime > IO_TIMEOUT)) break; } else { /* Set any zeroed pixels to the background color, * if a special background color is specified. */ if (background) for (cp=op, i=n; --i >= 0; cp++) if (!*cp) *cp = background; op += n; } } /* Refresh the display, if the current display frame is the * same as the reference frame. */ if (rf_p == df_p) { BRect fb_r, pw_r; fb_r.r_left = x * zoom; fb_r.r_top = y * zoom; fb_r.r_width = min (nbytes * zoom, fb_width); fb_r.r_height = ((nbytes*zoom*zoom + fb_width-1)/fb_width); Bpw_get_region_rect (gio_pw, &pw_rect); Bpw_lock (gio_pw, &pw_rect); pw_rect.r_left = df_p->fb_xoff; pw_rect.r_top = df_p->fb_yoff; if (maprect (&fb_rect, &fb_r, &pw_rect, &pw_r)) if (maprect (&pw_rect, &pw_r, &fb_rect, &fb_r)) { ds_write (gio_pw, pw_r.r_left, pw_r.r_top, pw_r.r_width, pw_r.r_height, PIX_SRC | PIX_COLOR(NGREY-1), df_p->fb_pr, fb_r.r_left, fb_r.r_top); if (pw_r.r_top + pw_r.r_height >= pw_rect.r_height - cb_height) put_colorbar(); } Bpw_unlock (gio_pw); } return (NOTIFY_DONE); } break; case WCS: /* Read or write the WCS for a frame. The frame number to * which the WCS applies is passed in Z and the frame buffer * configuration in T. The client changes the frame buffer * configuration in a WCS set. The WCS text follows the header * as byte packed ASCII data. */ if (iis.tid & IIS_READ) { /* Return the WCS for the referenced frame. */ char emsg[SZ_FNAME]; char *text; int frame; frame = decode_frameno (iis.z & 07777); if (frame > fb_nframes) strcpy (text=emsg, "[NOSUCHFRAME]\n"); else { set_reference_frame (frame); text = wcsbuf[reference_frame-1]; } write (dataout, text, SZ_WCSBUF); } else { /* Set the WCS for the referenced frame. */ char buf[1024]; int fb_config, frame; frame = decode_frameno (iis.z & 07777); if (frame > fb_nframes) if (frame < MAX_FRAMES) set_fbconfig (fb_config_index, frame); set_reference_frame (frame); if ((fb_config = iis.t & 077) != fb_config_index) set_fbconfig (fb_config, reference_frame); /* Read in and set up the WCS. */ if (read (datain, buf, ndatabytes) == ndatabytes) strncpy (wcsbuf[reference_frame-1], buf, SZ_WCSBUF); strcpy (rf_p->fb_ctran.format, W_DEFFORMAT); rf_p->fb_ctran.imtitle[0] = '\0'; rf_p->fb_ctran.valid = 0; rf_p->fb_imageno++; rf_p->fb_objno = 1; wcs_update (rf_p); if (rf_p == df_p) window_set (gio_frame, FRAME_LABEL, framelabel(), 0); } return (NOTIFY_DONE); break; case IMCURSOR: /* Read or write the logical image cursor. This is an extension * added to provide a high level cursor read facility; this is * not the same as a low level access to the IIS cursor subunit. * Cursor reads may be either nonblocking (immediate) or blocking, * using the keyboard or mouse to terminate the read, and * coordinates may be returned in either image (world) or frame * buffer pixel coordinates. */ if (iis.tid & IIS_READ) { /* Read the logical image cursor. In the case of a blocking * read all we do is initiate a cursor read; completion occurs * when the user hits a key or button. */ if (iis.tid & IMC_SAMPLE) { /* Sample the cursor position. */ register struct ctran *ct; int wcs = iis.z; int sx, sy; float wx, wy; wx = sx = last_sx + pw_rect.r_left; wy = sy = last_sy + pw_rect.r_top; if (wcs) { ct = wcs_update (df_p); if (ct->valid) { if (abs(ct->a) > .001) wx = ct->a * sx + ct->c * sy + ct->tx; if (abs(ct->d) > .001) wy = ct->b * sx + ct->d * sy + ct->ty; } } /* Return the cursor value on the output datastream encoded * in a fixed size ascii buffer. */ gio_retcursorval (wx, wy, display_frame*100+wcs, 0, ""); } else { /* Initiate a user triggered cursor read. */ gio_readcursor (iis.z); } } else { /* Write (set) the logical image cursor position. */ register struct ctran *ct; int sx = iis.x, sy = iis.y; float wx = sx, wy = sy; int wcs = iis.z; if (wcs) { ct = wcs_update (df_p); if (ct->valid) { if (abs(ct->a) > .001) sx = (wx - ct->tx) / ct->a; if (abs(ct->d) > .001) sy = (wy - ct->ty) / ct->d; } } gio_setcursorpos (sx - pw_rect.r_left, sy - pw_rect.r_top); } return (NOTIFY_DONE); break; default: /* Ignore unsupported command input. */ break; } /* Discard any data following the header. */ if (!(iis.tid & IIS_READ)) for (nbytes = ndatabytes; nbytes > 0; nbytes -= n) { n = (nbytes < SZ_FIFOBUF) ? nbytes : SZ_FIFOBUF; if ((n = read (datain, buf, n)) <= 0) break; } return (NOTIFY_DONE); } /* SET_REFERENCE_FRAME -- Set reference frame. If the frame referenced is * greater than the current number of frames, attempt to increase the number * of frames. */ static set_reference_frame (n) register int n; { reference_frame = max (1, n); if (reference_frame > fb_nframes) { if (reference_frame < MAX_FRAMES) set_fbconfig (fb_config_index, reference_frame); else { fprintf (stderr, "imtool warning: "); fprintf (stderr, "attempt to reference nonexistent frame %d\n", reference_frame); reference_frame = fb_nframes; } } rf_p = frames + (reference_frame - 1); } /* DECODE_FRAMENO -- Decode encoded IIS register frame number. */ static decode_frameno (z) register int z; { register int n; /* Get the frame number, encoded with a bit for each frame, 01 is * frame 1, 02 is frame 2, 04 is frame 3, and so on. */ if (!z) z = 1; for (n=0; !(z & 1); z >>= 1) n++; return (max (1, n + 1)); } /* BSWAP2 - Move bytes from array "a" to array "b", swapping successive * pairs of bytes. The two arrays may be the same but may not be offset * and overlapping. */ static bswap2 (a, b, nbytes) char *a, *b; /* input array */ int nbytes; /* number of bytes to swap */ { register char *ip=a, *op=b, *otop; register unsigned temp; /* Swap successive pairs of bytes. */ for (otop = op + (nbytes & ~1); op < otop; ) { temp = *ip++; *op++ = *ip++; *op++ = temp; } /* If there is an odd byte left, move it to the output array. */ if (nbytes & 1) *op = *ip; } /* Cursor and marker pixrects. */ static short p_imcursor[] = { #include "imtool.cursor" }; static short p_imcross[] = { #include "imtool.cross" }; static short p_imsquare[] = { #include "imtool.square" }; mpr_static (old_cursor, 16, 16, 1, NULL); mpr_static (pr_cursor, 16, 16, 1, p_imcursor); mpr_static (pr_cross, 16, 16, 1, p_imcross); mpr_static (pr_square, 16, 16, 1, p_imsquare); static struct pixrect *marker[] = { NULL, &pr_cursor, &pr_cross, &pr_square }; /* GIO_READCURSOR -- Initiate an image cursor read. Save the current * mouse coordinates if outside the imtool window, restore the mouse to the * imtool window, and change the cursor shape to indicate that a cursor read * is in progress. May be called while a cursor read is already in progress * to reset the cursor-read cursor pixrect. */ static gio_readcursor (wcs) int wcs; { Cursor cursor = window_get (gio_canvas, WIN_CURSOR); if (!reading_imcursor) { /* Save cursor pixrect for later restore. */ old_cursor = *((Pixrect *) cursor_get (cursor, CURSOR_IMAGE)); /* Save the absolute mouse position so that we can restore it when * the cursor read is completed. Restore the mouse to the most * recent position in the IMTOOL window. */ get_absmousepos (gio_frame_fd, &save_sx, &save_sy); gio_setcursorpos (last_sx, last_sy); reading_imcursor++; imcursor_wcs = wcs; } /* Change the cursor shape while the cursor read is in progress. */ cursor_set (cursor, CURSOR_IMAGE, &pr_cursor, CURSOR_SHOW_CURSOR, TRUE, CURSOR_SHOW_CROSSHAIRS, FALSE, CURSOR_OP, PIX_NOT(PIX_SRC) & PIX_DST | PIX_COLOR(CMS_CURSOR), CURSOR_XHOT, 8, CURSOR_YHOT, 8, 0); window_set (gio_canvas, WIN_CURSOR, cursor, 0); } /* GIO_RESTORECURSOR -- Restore the original cursor. */ static gio_restorecursor() { if (reading_imcursor) { Cursor cursor; /* Restore the mouse position to whatever it was before IMTOOL * grabbed the mouse for the cursor read. */ set_absmousepos (gio_frame_fd, save_sx, save_sy); /* Restore the default IMTOOL cursor shape. */ cursor = window_get (gio_canvas, WIN_CURSOR); cursor_set (cursor, CURSOR_IMAGE, &old_cursor, CURSOR_SHOW_CURSOR, FALSE, CURSOR_SHOW_CROSSHAIRS, (cursor_show == CURSOR_ON), 0); window_set (gio_canvas, WIN_CURSOR, cursor, 0); reading_imcursor = 0; } } /* GIO_RETCURSORVAL -- Return the cursor value on the output datastream to * the client which requested the cursor read. */ static gio_retcursorval (wx, wy, wcs, key, strval) float wx, wy; /* cursor coordinates */ int wcs; /* encoded WCS value */ int key; /* keystroke used as trigger */ char *strval; /* optional string value */ { char curval[SZ_IMCURVAL]; char keystr[20]; /* Encode the cursor value. */ if (key == EOF) sprintf (curval, "EOF\n"); else { if (isprint (key) && !isspace(key)) { keystr[0] = key; keystr[1] = '\0'; } else sprintf (keystr, "\\%03o", key); sprintf (curval, "%10.3f %10.3f %d %s %s\n", wx, wy, wcs, keystr, strval); } /* Send it to the client program. */ write (dataout, curval, sizeof(curval)); } /* EV_GIOFRAME -- GIO frame event handler. */ static Notify_value ev_gioframe (frame, event, arg, type) Frame frame; Event *event; Notify_arg arg; Notify_event_type type; { Notify_value value; value = notify_next_event_func (frame, event, arg, type); window_open = (((int) window_get (gio_frame, FRAME_CLOSED)) == 0); return (value); } /* EV_GIOINPUT -- GIO input event handler. */ static Notify_value ev_gioinput (frame, event, arg, type) Frame frame; Event *event; Notify_arg arg; Notify_event_type type; { register int key; Notify_value value; static float xsize, ysize; BRect rect; char ch; key = event_id (event); /* The following is to attempt to restore the image greyscale in the * global color map, after the color map has been clobbered by the * window manager when the mouse is moved to some other window. */ if (key == KBD_DONE || key == LOC_WINEXIT) { edit_colormap(); return (NOTIFY_DONE); } /* Let frame operate upon the event. */ if ((int)type != PANNER_EVENT) value = notify_next_event_func (frame, event, arg, type); switch (key) { case WIN_RESIZE: Bpw_get_region_rect (gio_pw, &pw_rect); pw_rect.r_left = df_p->fb_xoff = max(0, min(fb_rect.r_width - pw_rect.r_width, df_p->fb_xoff)); pw_rect.r_top = df_p->fb_yoff = max(0, min(fb_rect.r_height - pw_rect.r_height, df_p->fb_yoff)); gio_xsize = pw_rect.r_width; gio_ysize = pw_rect.r_height; init_colorbar (pw_rect.r_width); wc_xoff = wc_yoff = 0; if (display_coords && state == TRACK_CURSOR) update_coords (event); break; case KEY_SNAP: /* Imcopy. */ imagecopy_proc(); break; case KEY_PCOORDS: /* Enable/disable continuous display of the cursor coordinates. */ toggle_displaycoords (event); break; case KEY_SETUP: /* Toggle display of the setup panel. */ setup_proc(); break; case KEY_REMARK: /* Remark a list of objects. */ if (event_is_down(event)) { char fname[SZ_FNAME]; wcs_update (df_p); o_revtext = !o_revtext; sprintf (fname, o_fname, df_p->fb_frameno, df_p->fb_imageno); strcpy (fname, getfname(fname, 0)); remark_objects (fname); } break; case MS_RIGHT: if (event_is_down(event)) { last_sx = last_bx = event_x(event); last_sy = last_by = event_y(event); } /* If the cursor is moved while the right mouse button is * depressed the image is windowed. If the control key is also * depressed the cursor is used to roam about in the frame buffer. */ if (state == TRACK_CURSOR && event_is_down(event)) { if (event_ctrl_is_down (event)) state = ROAM; else state = WINDOW; xsize = pw_rect.r_width; ysize = pw_rect.r_height; if (state == WINDOW) { switch (df_p->fb_maptype) { case MONO: case HEAT: case RAMP1: case RAMP2: case HALLEY: case LINEARPS: case ULUT1: case ULUT2: compute_transfer_function (event); break; case RANDOMPS: case CRANDOMPS: set_colortable(); break; } set_transfer_function (gio_pw, df_p->fb_center, df_p->fb_slope); } } else if (state != TRACK_CURSOR && event_is_up(event)) state = TRACK_CURSOR; break; case LOC_DRAG: last_sx = event_x (event); last_sy = event_y (event); if (panning) p_cursor_setback--; if (state == WINDOW) { compute_transfer_function (event); set_transfer_function (gio_pw, df_p->fb_center, df_p->fb_slope); } break; case LOC_MOVE: last_sx = event_x (event); last_sy = event_y (event); if (panning) p_cursor_setback--; if (display_coords && state == TRACK_CURSOR) update_coords (event); break; case MS_LEFT: last_sx = event_x (event); last_sy = event_y (event); if (event_is_down (event)) { if (reading_imcursor) { /* The left mouse button may be used to alias keyboard * events. Typing ctrl/button causes the last key to be * aliased with the indicated button. Thereafter, pressing * that mouse button during a cursor read causes the cursor * read to terminate, returning the aliased key just as if * the key had been typed on the keyboard. */ if (event_ctrl_is_down (event)) { if (key == MS_LEFT) key_left = last_key; } else if (reading_imcursor) { if (key == MS_LEFT) key = key_left; if (key) goto readcur; } } else if (display_coords && state==TRACK_CURSOR) { /* Add an object to a cursor list. */ mark_object (event); } } break; case MS_MIDDLE: /* Pan - move the object under the cursor to the center of the * display window (or as close as possible without wraparound). */ if (event_is_up (event)) { int fb_ex, fb_ey, fb_mx, fb_my, fb_xc, fb_yc, fb_nx, fb_ny; int pw_xc, pw_yc, dx, dy, n_x, n_y; int newzoom, close=1; /* Pressing the middle button without moving the mouse causes * the zoom factor to be advanced. In other words, placing * the mouse on a feature and pressing the "zoom/pan" button * causes that feature to be moved to the center of the * display; pressing the button again causes the display to be * zoomed about the centered feature. */ newzoom = zoom; n_x = event_x(event); n_y = event_y(event); if (abs(n_x-last_bx) <= close && abs(n_y-last_by) <= close) { if (++zoom_index >= nzooms) zoom_index = 0; newzoom = zooms[zoom_index]; } last_sx = last_bx = n_x; last_sy = last_by = n_y; pw_xc = pw_rect.r_width / 2; /* window center in pw */ pw_yc = pw_rect.r_height / 2; fb_mx = pw_rect.r_left + n_x; /* final mouse position */ fb_my = pw_rect.r_top + n_y; fb_xc = pw_rect.r_left + pw_xc; /* window center in fb */ fb_yc = pw_rect.r_top + pw_yc; fb_nx = fb_ex = fb_mx; /* next center */ fb_ny = fb_ey = fb_my; dx = n_x - pw_xc; /* step size */ dy = n_y - pw_yc; /* Pan a long ways in the indicated direction, normally to the * edge of the image. */ if (event_shift_is_down (event)) { fb_ex = fb_nx = fb_mx = max(pw_xc, min(fb_rect.r_width - pw_xc, fb_xc + dx*5)); fb_ey = fb_ny = fb_my = max(pw_xc, min(fb_rect.r_height - pw_yc, fb_yc + dy*5)); if (!event_ctrl_is_down (event)) dx = dy = 0; } /* Smooth pan to ex,ey. May be combined with shift-pan. */ if (event_ctrl_is_down (event)) { dx = dx ? dx / abs(dx) : 0; dy = dy ? dy / abs(dy) : 0; /* Increase step size if window is large. */ if (pw_rect.r_width * pw_rect.r_height > 200000) { dx *= 2; dy *= 2; } fb_nx = max(0, min(fb_rect.r_width, fb_xc + dx)); fb_ny = max(0, min(fb_rect.r_height, fb_yc + dy)); } /* Go to x,y starting at nx,ny stepping dx,dy per frame. */ if (fb_nx != fb_xc || fb_ny != fb_yc || zoom != newzoom) start_pan (fb_mx,fb_my, fb_nx,fb_ny, fb_ex,fb_ey, dx,dy, newzoom); } break; case INTERRUPT: /* Abort any lengthy operation currently in progress. */ if (reading_imcursor) goto readcur; else stop_pan(); break; case NEXT_SCREEN: /* Display the next screen in numerical sequence. */ set_frame (0); if (display_coords && state == TRACK_CURSOR) update_coords (event); break; case PREV_SCREEN: /* Display the previous screen in numerical sequence. */ set_frame (-1); if (display_coords && state == TRACK_CURSOR) update_coords (event); break; case CYCLE_BLINK: /* Display the next screen from the blink frames list. * The frames in the blink frame list do not have to exist; * if not, then advance through the list until either a valid * frame is found, or the list has been traversed once. */ if (n_blink_frames > 0 && window_open) { int frame, n; for (n=n_blink_frames; --n >= 0; ) { if (++blink_frame >= n_blink_frames) blink_frame = 0; frame = blink_frames[blink_frame]; if (frame >= 1 && frame <= fb_nframes) { set_frame (frame); if (display_coords && state == TRACK_CURSOR) update_coords (NULL); break; } } } break; default: /* Terminate a cursor read, returning the encoded cursor value * sequence to client program on the output datastream. */ if (event_is_down(event) && (event_is_ascii(event) || event_is_key_right(event))) { readcur: last_sx = event_x (event); last_sy = event_y (event); /* Terminate cursor read? */ if (reading_imcursor) { register struct ctran *ct; int wcs = imcursor_wcs; int sx, sy; float wx, wy; /* Map keypad function keys to digits. */ if (event_is_key_right(event)) { switch (key = event_id(event) - KEY_RIGHT(1) + 1) { case 7: case 8: case 9: break; case 10: case 11: case 12: key -= 6; break; case 13: case 14: case 15: key -= 12; break; default: return (value); } key += '0'; } last_x = event_x (event); last_y = event_y (event); last_key = key; wx = sx = last_x + pw_rect.r_left; wy = sy = last_y + pw_rect.r_top; if (wcs) { ct = wcs_update (df_p); if (ct->valid) { if (abs(ct->a) > .001) wx = sx * ct->a + ct->tx; if (abs(ct->d) > .001) wy = sy * ct->d + ct->ty; } } /* Map ctrl/d and ctrl/z into EOF. */ if (key == '\004' || key == '\032') key = EOF; else if (marktype) { /* Mark the cursor position? */ edit_framebuffer (df_p, sx/zoom - 8, sy/zoom - 8, marker[marktype], PIX_NOT(PIX_SRC) & PIX_DST); } /* Return the cursor value on the output datastream encoded * in a fixed size ascii buffer. */ gio_retcursorval (wx, wy, display_frame*100+wcs, key, ""); /* Terminate the cursor read. */ gio_restorecursor(); } } } return (value); } static int p_dx, p_dy; static int p_sx, p_sy; static int p_left, p_top; static int p_svdc; /* START_PAN -- Pan the image smoothly to the indicated position. This can * take a while, so we want to do it on a timer and provide for interrupt. * A new pan can be started to change the destination while an old pan is * still in progress. */ static start_pan (fb_mx,fb_my, fb_nx,fb_ny, fb_ex,fb_ey, dx,dy, newzoom) int fb_mx, fb_my; /* mouse position in frame buffer */ int fb_nx, fb_ny; /* center of window at next display */ int fb_ex, fb_ey; /* center of window at final display */ int dx, dy; /* step size for pan */ register int newzoom; /* new zoom factor */ { register int w, h; int n_left, n_top; int n_sx, n_sy, e_sx, e_sy; if (!panning) { p_svdc = display_coords; display_coords = 0; panning++; } p_cursor_setback = 9; gio_setcursor (CURSOR_OFF, 0); Bpw_get_region_rect (gio_pw, &pw_rect); w = pw_rect.r_width; h = pw_rect.r_height; /* Scale zoomed frame buffer units to new zoom factor. */ p_sx = fb_mx * newzoom / zoom; p_sy = fb_my * newzoom / zoom; n_sx = fb_nx * newzoom / zoom; n_sy = fb_ny * newzoom / zoom; e_sx = fb_ex * newzoom / zoom; e_sy = fb_ey * newzoom / zoom; p_dx = dx * newzoom; p_dy = dy * newzoom; /* The following are the final left,top values. */ p_left = max(0, min(Fb_width*newzoom - w, (e_sx - w/2) / newzoom * newzoom)); p_top = max(0, min(Fb_height*newzoom - h, (e_sy - h/2) / newzoom * newzoom)); /* The following are the left,top values for the next display. */ n_left = max(0, min(Fb_width*newzoom - w, (n_sx - w/2) / newzoom * newzoom)); n_top = max(0, min(Fb_height*newzoom - h, (n_sy - h/2) / newzoom * newzoom)); /* Set the new zoom factor for the display. */ set_zoom (df_p, n_left, n_top, newzoom); notify_post_event (ev_panner, NULL, NOTIFY_SAFE); } /* STOP_PAN -- Called to abort a pan. */ static stop_pan() { p_dx = p_dy = 0; } /* PANNER -- Called on a fast timer to do the panning. */ static Notify_value ev_panner() { register int left, top; /* No clipping is done, so the imtool window must be exposed. */ window_set (gio_frame, WIN_SHOW, TRUE, 0); /* repaint (P_IMAGE|P_DONTCLIP); */ repaint (P_IMAGE); if (p_dx < 0 && pw_rect.r_left <= p_left || p_dx > 0 && pw_rect.r_left >= p_left) p_dx = 0; else if (p_dx) { left = pw_rect.r_left + p_dx; if (p_dx < 0) left = max (p_left, left); else left = min (p_left, left); df_p->fb_xoff = pw_rect.r_left = left; } if (p_dy < 0 && pw_rect.r_top <= p_top || p_dy > 0 && pw_rect.r_top >= p_top) p_dy = 0; else if (p_dy) { top = pw_rect.r_top + p_dy; if (p_dy < 0) top = max (p_top, top); else top = min (p_top, top); df_p->fb_yoff = pw_rect.r_top = top; } if (p_dx == 0 && p_dy == 0) { if (panning) { panning = 0; display_coords = p_svdc; if (p_cursor_setback > 0) { int sx = p_sx - pw_rect.r_left; int sy = p_sy - pw_rect.r_top; if (sx >= 0 && sx < pw_rect.r_width && sy >= 0 && sy < pw_rect.r_height) gio_setcursorpos (sx, sy); gio_setcursor (CURSOR_ON, 0); gio_events(); } repaint (P_GRAPHICS|P_COLORBAR); } } else { /* Allow the window to process any pending events. */ gio_events(); /* Post another call to the panner. */ notify_post_event (ev_panner, NULL, NOTIFY_SAFE); } return (NOTIFY_DONE); } /* EDIT_FRAMEBUFFER -- Edit a frame buffer by operating upon it with the * given pixrect and rasterop at the given location, clipping as necessary * at the boundaries of the frame. Update the display window as well, if * the frame being edited is the display frame. */ static edit_framebuffer (fb, x, y, pr, rop) struct framebuf *fb; /* frame to be edited */ int x, y; /* left,top coords of rect to be edited */ struct pixrect *pr; /* pixrect to be used */ int rop; /* rasterop defining operation */ { int width = pr->pr_width, height = pr->pr_height; int s_left = 0, s_top = 0; int d_left = x, d_top = y; /* Clip to the frame boundary. */ while (d_left < 0) { s_left++; width--; d_left++; } while (d_left + width-1 > Fb_width) width--; while (d_top < 0) { s_top++; height--; d_top++; } while (d_top + height-1 > Fb_height) height--; /* All done if there is nothing left after clipping. */ if (width*height <= 0) return; /* Edit the frame buffer (clobbers the display pixels). */ pr_rop (fb->fb_pr, d_left, d_top, width, height, PIX_NOT(PIX_SRC) & PIX_DST, pr, s_left, s_top); /* Refresh the display, if the current display frame is the * same as the reference frame. */ if (fb == df_p) { BRect fb_r, pw_r; fb_r.r_left = d_left * zoom; fb_r.r_top = d_top * zoom; fb_r.r_width = width * zoom; fb_r.r_height = height * zoom; Bpw_get_region_rect (gio_pw, &pw_rect); Bpw_lock (gio_pw, &pw_rect); pw_rect.r_left = df_p->fb_xoff; pw_rect.r_top = df_p->fb_yoff; if (maprect (&fb_rect, &fb_r, &pw_rect, &pw_r)) if (maprect (&pw_rect, &pw_r, &fb_rect, &fb_r)) { ds_write (gio_pw, pw_r.r_left, pw_r.r_top, pw_r.r_width, pw_r.r_height, PIX_SRC | PIX_COLOR(NGREY-1), df_p->fb_pr, fb_r.r_left, fb_r.r_top); if (pw_r.r_top + pw_r.r_height >= pw_rect.r_height - cb_height) put_colorbar(); } Bpw_unlock (gio_pw); } } /* GIO_EVENTS -- Have the image window process any queued input events. */ static gio_events() { Event event; int fd, flags; /* Allow the window to process any pending events. */ fd = (int) window_get (gio_canvas, WIN_FD); flags = fcntl (fd, F_GETFL, 0); fcntl (fd, F_SETFL, O_NDELAY); while (window_read_event (gio_canvas, &event) != -1) ev_gioinput (gio_canvas, canvas_event(gio_canvas, &event), NULL, PANNER_EVENT); fcntl (fd, F_SETFL, flags); } /* ICLEAR_PROC -- Clear the main (image) window. */ static iclear_proc() { erase (df_p); } /* GCLEAR_PROC -- Clear the graphics overlay. */ static gclear_proc() { df_p->fb_objno = 1; repaint (P_IMAGE|P_COLORBAR); } /* SETFRAME_PROC -- Select the next frame for viewing. */ static setframe_proc() { set_frame (0); } /* SET_FRAME -- Set the display frame. Call with frameno=0 to advance to * the next frame, -N will yield the previous frame in sequence, and * anything else is actual frame number. */ static set_frame (frameno) int frameno; { if (frameno < 0) { frameno = display_frame - 1; if (frameno < 1) frameno = fb_nframes; } else if (frameno == 0) { frameno = display_frame + 1; if (frameno > fb_nframes) frameno = 1; } else { if (frameno < 1) frameno = 1; else if (frameno > fb_nframes) frameno = fb_nframes; } display_frame = frameno; df_p = frames + (frameno - 1); set_zoom (df_p, df_p->fb_xoff, df_p->fb_yoff, df_p->fb_xzoom); set_colortable(); set_transfer_function (gio_pw, df_p->fb_center, df_p->fb_slope); window_set (gio_frame, FRAME_LABEL, framelabel(), 0); panel_set_value (pan_set_maptype, df_p->fb_maptype); repaint (P_IMAGE|P_COLORBAR|P_GRAPHICS); } /* SET_ZOOM -- Change the zoom factor for the referenced frame to the given * value. If the referenced frame is the display frame, update the global * display zoom factors as well. */ static set_zoom (fr, left, top, newzoom) register struct framebuf *fr; /* frame to be zoomed */ int left, top; /* new left and top for frame */ int newzoom; /* new zoom factor */ { register struct ctran *ct; int fb_zoom, i; /* Verify valid zoom factor. */ newzoom = max(zooms[0], min(zooms[nzooms-1], newzoom)); for (i=0; i < nzooms; i++) if (zooms[i] == newzoom) { zoom_index = i; break; } /* Set the new frame buffer zoom factor. */ if ((fb_zoom = fr->fb_xzoom) != newzoom) { ct = &fr->fb_ctran; ct->a = ct->a * fb_zoom / newzoom; ct->d = ct->d * fb_zoom / newzoom; /* For Apply a 0.5 pixel correction when zooming, to make the * center of the pixel have integral coordinates (coord X,Y where * X and Y are integral will always be the center of a pixel). * This should be turned off for zoom=1, since there is no * subpixel resolution, or if the image has already been zoomed * at the host level. */ if (abs(ct->a * newzoom) < 1.01) { if (fb_zoom == 1) ct->tx += (ct->a > 0) ? -0.5 : 0.5; else if (newzoom == 1) ct->tx += (ct->a > 0) ? 0.5 : -0.5; } if (abs(ct->d * newzoom) < 1.01) { if (fb_zoom == 1) ct->ty += (ct->d > 0) ? -0.5 : 0.5; else if (newzoom == 1) ct->ty += (ct->d > 0) ? 0.5 : -0.5; } fr->fb_xzoom = fr->fb_yzoom = newzoom; } /* Offsets must be aligned to an unzoomed frame buffer pixel * boundary since this constraint is applied in ds_write. */ fr->fb_xoff = max(0, min(Fb_width*newzoom - pw_rect.r_width, left / newzoom * newzoom)); fr->fb_yoff = max(0, min(Fb_height*newzoom - pw_rect.r_height, top / newzoom * newzoom)); /* If the referenced frame is the display frame, make the new zoom * factor global. */ if (fr == df_p) { fb_width = Fb_width * newzoom; fb_height = Fb_height * newzoom; fb_rect.r_top = 0; fb_rect.r_left = 0; fb_rect.r_width = fb_width; fb_rect.r_height = fb_height; pw_rect.r_left = df_p->fb_xoff; pw_rect.r_top = df_p->fb_yoff; zoom = newzoom; } } /* ERASE -- Clear a frame. */ static erase (fr) struct framebuf *fr; { register int *op, v, n; unsigned char *cp; int val; for (val=0, n=sizeof(int), cp = (unsigned char *)&val; --n >= 0; ) *cp++ = background; if (val) { op = (int *) mpr_d(fr->fb_pr)->md_image; n = Fb_width * Fb_height / sizeof(int); for (v=val; --n >= 0; ) *op++ = v; } else bzero ((char *)mpr_d(fr->fb_pr)->md_image, Fb_width * Fb_height); if (fr == df_p) repaint (P_IMAGE|P_COLORBAR); } /* REPAINT -- Repaint the display window. */ static repaint (what) int what; { if (what & P_IMAGE) { BRect fb_r, pw_r; int rop; pw_r = pw_rect; pw_r.r_left = pw_r.r_top = 0; if (what & P_COLORBAR) pw_r.r_height -= cb_height; rop = PIX_SRC | PIX_COLOR(NGREY-1); if (what & P_DONTCLIP) rop |= PIX_DONTCLIP; if (maprect (&pw_rect, &pw_r, &fb_rect, &fb_r)) if (maprect (&fb_rect, &fb_r, &pw_rect, &pw_r)) ds_write (gio_pw, pw_r.r_left, pw_r.r_top, pw_r.r_width, pw_r.r_height, rop, df_p->fb_pr, fb_r.r_left, fb_r.r_top); if (display_coords && state == TRACK_CURSOR) { set_wcsboxpos(); pw_text (gio_pw, wc_xoff, wc_yoff + wc_font->pf_defaultsize.y, PIX_NOT(PIX_SRC), wc_font, wc_text); } } if (what & P_COLORBAR) put_colorbar(); if ((what & P_GRAPHICS) && df_p->fb_objno > 1) { char fname[SZ_FNAME]; wcs_update (df_p); sprintf (fname, o_fname, df_p->fb_frameno, df_p->fb_imageno); strcpy (fname, getfname(fname, 0)); remark_objects (fname); } } /* REFRESH_DISPLAY -- Called by the windowing system when the display needs * to be refreshed from the frame buffer. */ static refresh_display (canvas, pw, rl) Canvas canvas; Pixwin *pw; Rectlist *rl; { register struct rectnode *rn; BRect fb_r, pw_r; Rect rect, r; /* See if any damage has occurred and fix it. */ rl_rectoffset (rl, &rl->rl_bound, &rect); pw_lock (pw, &rect); /* Now fix all the damage. Regions of the display window which are * not mapped onto the frame buffer are not fixed up at present. * Scale changes (zoom/dezoom) are not currently immplemented. */ for (rn = rl->rl_head; rn; rn = rn->rn_next) { rl_rectoffset (rl, &rn->rn_rect, &r); pw_r.r_left = r.r_left; pw_r.r_top = r.r_top; pw_r.r_width = r.r_width; pw_r.r_height = r.r_height; if (maprect (&pw_rect, &pw_r, &fb_rect, &fb_r)) if (maprect (&fb_rect, &fb_r, &pw_rect, &pw_r)) ds_write (pw, pw_r.r_left, pw_r.r_top, pw_r.r_width, pw_r.r_height, PIX_SRC | PIX_COLOR(NGREY-1), df_p->fb_pr, fb_r.r_left, fb_r.r_top); } put_colorbar(); pw_unlock (pw); } /* DS_WRITE -- Write to the display. This is analogous to pw_write, except * that pixel replication or subsampling is performed as indicated by the * zoom factors for the current display frame. At present, the zoom factor * may not be specified independently for x and y. */ static ds_write (pw, left, top, width, height, rop, fb_pr, fb_left, fb_top) Pixwin *pw; int left, top; int width, height; int rop; Pixrect *fb_pr; int fb_left, fb_top; /* zoomed frame buffer coords */ { register unsigned char pix, *ip, *op; register int n, p; unsigned char *otop, *fb, *lp; int pr_left, pr_top, i, j; Pixrect *mpr_line, *pr; struct rect pw_r; if (width <= 0 || height <= 0) return; /* If no zoom, just copy the frame buffer rect to the screen. */ if (zoom <= 1) { pw_write (pw, left,top, width,height, rop, fb_pr, fb_left,fb_top); return; } /* Zoom - magnify the image by pixel replication. (This assumes an * 8 bit frame buffer and screen pixrect). */ mpr_line = mem_create (width, 1, pw->pw_pixrect->pr_depth); fb = (unsigned char *)mpr_d(df_p->fb_pr)->md_image; lp = (unsigned char *)mpr_d(mpr_line)->md_image; otop = lp + width; /* Lock the frame buffer to avoid scribbling on other windows * during write to raw screen.. */ pw_get_region_rect (pw, &pw_r); pw_lock (pw, &pw_r); pr = pw->pw_pixrect; pr_left = left + (int)window_get(gio_frame, WIN_X) + TOOL_BORDERWIDTH; pr_top = top + (int)window_get(gio_frame, WIN_Y) + HEIGHTADJUST - TOOL_BORDERWIDTH; for (j=0, i=(fb_top/zoom); j < height; j += zoom) { ip = fb + (i++ * Fb_width) + (fb_left/zoom); op = lp; /* Replicate a block of pixels. */ switch (zoom) { case 2: for (n = (width/2); --n >= 0; ) { pix = *ip++; *op++ = pix; *op++ = pix; } break; case 3: for (n = (width/3); --n >= 0; ) { pix = *ip++; *op++ = pix; *op++ = pix; *op++ = pix; } break; case 4: for (n = (width/4); --n >= 0; ) { pix = *ip++; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; } break; case 5: for (n = (width/5); --n >= 0; ) { pix = *ip++; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; } break; case 6: for (n = (width/6); --n >= 0; ) { pix = *ip++; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; } break; case 7: for (n = (width/7); --n >= 0; ) { pix = *ip++; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; } break; case 8: for (n = (width/8); --n >= 0; ) { pix = *ip++; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; *op++ = pix; } break; default: for (n = (width/zoom); --n >= 0; ) { pix = *ip++; for (p=zoom; --p >= 0; ) *op++ = pix; } break; } /* Fill the last partial pixel. */ pix = *ip++; while (op < otop) *op++ = pix; pr_replrop (pr, pr_left,pr_top+j, width, min (height-j, zoom), rop, mpr_line, 0,0); } pw_unlock (pw); pr_close (mpr_line); } /* PUT_COLORBAR -- Refresh the colorbar on the screen. */ static put_colorbar() { if (cb_height) pw_write (gio_pw, 0, pw_rect.r_height - cb_height, min (pw_rect.r_width, Fb_width), cb_height, PIX_SRC, cb_pr, 0, 0); } /* TOGGLE_DISPLAYCOORDS -- Enable/disable continuous display of the cursor * coordinates. */ static toggle_displaycoords (event) Event *event; { BRect fb_r, pw_r; if (display_coords) { /* Enable mouse moved input events. */ window_set (gio_canvas, WIN_IGNORE_PICK_EVENTS, LOC_MOVE, 0, 0); display_coords = 0; /* Refresh the region of the screen used to output coordinates * from the frame buffer, erasing the coordinate output box. */ pw_r.r_left = wc_xoff; pw_r.r_top = wc_yoff; pw_r.r_width = wc_width; pw_r.r_height = wc_height; if (maprect (&pw_rect, &pw_r, &fb_rect, &fb_r)) ds_write (gio_pw, wc_xoff, wc_yoff, wc_width, wc_height, PIX_SRC | PIX_COLOR(NGREY-1), df_p->fb_pr, fb_r.r_left, fb_r.r_top); } else { /* Disable mouse moved input events. */ window_set (gio_canvas, WIN_CONSUME_PICK_EVENTS, LOC_MOVE, 0, 0); display_coords = 1; update_coords (event); } } /* UPDATE_COORDS -- Compute and output the world coordinates of the given * event, using the WCS specified for the current display window. If called * with event=NULL the most recent locator position is used. */ static update_coords (event) Event *event; { register struct ctran *ct; static struct timeval o_tv; unsigned char *fb, *ip; struct timeval n_tv; int sx, sy, sz, fb_x, fb_y, delta_msec; char buf[1024], ch; float wx, wy, wz; /* Get frame buffer x,y; ignore events that occur faster than we * can update the coordinate readout. */ if (event) { /* Ignore event if it comes too soon. */ n_tv = event_time(event); if (o_tv.tv_sec) { delta_msec = ((n_tv.tv_sec - o_tv.tv_sec) * 1000 + (n_tv.tv_usec - o_tv.tv_usec) / 1000); if (delta_msec < 50) return; } /* Get the screen (window relative) coordinates of the event. */ sx = event_x(event) + pw_rect.r_left; sy = event_y(event) + pw_rect.r_top; } else { sx = last_sx + pw_rect.r_left; sy = last_sy + pw_rect.r_top; } /* Get frame buffer pixel value. */ fb = (unsigned char *) mpr_d (df_p->fb_pr)->md_image; fb_x = max(0, min(Fb_width, sx/zoom)); fb_y = max(0, min(Fb_height, sy/zoom)); sz = fb[fb_y*Fb_width+fb_x]; if (sz < CMS_DATASTART || sz > CMS_DATAEND) sz = 0; /* Compute the world coordinates of the event. */ ct = wcs_update (df_p); if (ct->valid) { wx = ct->a * sx + ct->c * sy + ct->tx; wy = ct->b * sx + ct->d * sy + ct->ty; if (sz == 0) wz = 0.0; else { switch (ct->zt) { case W_LINEAR: wz = ((sz - CMS_DATASTART) * (ct->z2 - ct->z1) / (CMS_DATARANGE-1)) + ct->z1; break; default: wz = sz; break; } } } else { wx = sx; wy = sy; wz = sz; } /* Get the font to be used. */ if (wc_font == NULL) { static char fontname[] = TEXT_FONT; if ((wc_font = pf_open (fontname)) == NULL) fprintf (stderr, "cannot open %s\n", fontname); wc_xoff = wc_yoff = 0; } ch = ' '; if (sz && ct->valid) { if (ct->z1 < ct->z2) { if (wz < (ct->z1 + 0.01)) ch = '-'; else if (wz > (ct->z2 - 0.01)) ch = '+'; } else if (ct->z1 > ct->z2) { if (wz < (ct->z2 + 0.01)) ch = '-'; else if (wz > (ct->z1 - 0.01)) ch = '+'; } } set_wcsboxpos(); sprintf (buf, ct->format, wx, wy, wz, ch); strncpy (wc_text, buf, SZ_WCTEXT); pw_text (gio_pw, wc_xoff, wc_yoff + wc_font->pf_defaultsize.y, PIX_NOT(PIX_SRC), wc_font, wc_text); if (event) o_tv = n_tv; } /* MARK_OBJECT -- Called when the user has clicked on the position of an * object to be marked and/or added to the output coordinate list. */ static mark_object (event) Event *event; { register struct ctran *ct; char tx_buf[SZ_FNAME]; char fname[SZ_FNAME]; int sx, sy, newset; float wx, wy; FILE *fp; ct = wcs_update (df_p); /* Get name of coordinate output file for the current frame. */ sprintf (tx_buf, o_fname, df_p->fb_frameno, df_p->fb_imageno); strcpy (fname, getfname(tx_buf, 0)); /* Append to the existing coordinate list, if any. If appending * to an existing coordinate list, the existing list is displayed * and the objno counter is left set to the next object to be added. */ if (newset = (df_p->fb_objno <= 1)) remark_objects (fname); if ((fp = fopen (fname, "a")) == NULL) { fprintf (stderr, "cannot open %s for appending\n", fname); return; } /* Timestamp the first entry in the output file. */ if (newset) timestamp (fp); /* Get the screen (window relative) coordinates of the event. */ sx = event_x(event) + pw_rect.r_left; sy = event_y(event) + pw_rect.r_top; /* Compute the world coordinates of the event. */ if (ct->valid) { wx = ct->a * sx + ct->c * sy + ct->tx; wy = ct->b * sx + ct->d * sy + ct->ty; } else { wx = sx; wy = sy; } /* Mark the object position on the screen. */ sprintf (tx_buf, "%d", df_p->fb_objno++); draw_text (sx - pw_rect.r_left, sy - pw_rect.r_top, tx_buf); fprintf (fp, "%g %g\n", wx, wy); fclose (fp); } /* REMARK_OBJECTS -- Read a object list file and mark the numbered objects * therein. */ static remark_objects (fname) char *fname; { register struct ctran *ct; register char *ip; char lbuf[SZ_LINE], tx_buf[SZ_FNAME]; int sx, sy, objno=1; float wx, wy; char *fgets(); FILE *fp; gclear_proc(); window_set (gio_frame, FRAME_LABEL, framelabel(), 0); if ((fp = fopen (fname, "r")) == NULL) return; while (fgets (lbuf, SZ_LINE, fp) != NULL) { /* Skip comment lines and blank lines. */ for (ip=lbuf; *ip == ' ' || *ip == '\t'; ip++) ; if (*ip == '\n' || *ip == '#') continue; if (!isdigit (*ip) && *ip != '-') continue; if (sscanf (ip, "%f%f", &wx, &wy) < 2) continue; sx = wx; sy = wy; /* Compute the world coordinates of the event if we have a valid * WCS transform (rotations not permitted)/ */ ct = wcs_update (df_p); if (ct->valid) { if (abs(ct->a) > .001) sx = (wx - ct->tx) / ct->a; if (abs(ct->d) > .001) sy = (wy - ct->ty) / ct->d; } /* Mark the object position on the screen. */ sprintf (tx_buf, "%d", objno++); draw_text (sx - pw_rect.r_left, sy - pw_rect.r_top, tx_buf); } fclose (fp); /* If we are updating an existing coordinate list from a newly * displayed frame, timestamp the new section of the list. */ if (df_p->fb_objno <= 1) if ((fp = fopen (fname, "a")) != NULL) { timestamp (fp); fclose (fp); } df_p->fb_objno = objno; } /* TIMESTAMP -- Timestamp the output stream. */ static timestamp (fp) FILE *fp; { register char *op; char obuf[SZ_LINE]; long clock; clock = time(0); fprintf (fp, "# %s", asctime(localtime(&clock))); sprintf (obuf, "# %s", df_p->fb_label); for (op=obuf; *op && *op != '\n'; op++) ; *op++ = '\n'; *op = '\0'; fputs (obuf, fp); } /* DRAW_TEXT -- Draw some text on the frame at the indicated position. */ static draw_text (x, y, text) int x, y; /* position where text is to be drawn */ char *text; /* the text */ { static struct pixfont *font = NULL; /* Get the screen font to be used. */ if (font == NULL) { static char fontname[] = MARK_FONT; if ((font = pf_open (fontname)) == NULL) fprintf (stderr, "cannot open %s\n", fontname); } /* Draw the text. */ if (o_revtext) pw_text (gio_pw, x, y, PIX_NOT(PIX_SRC) & PIX_DST, font, text); else pw_text (gio_pw, x, y, PIX_SRC | PIX_DST, font, text); } /* WCS_UPDATE -- Load the screen WCS, if not yet validated, from the user * wcs file, if any. * * File format (two lines): * * image title (imtool header label string)\n * a b c d tx ty z1 z2 zt * * NOTE: the WCS text is now passed in via the data stream as a write to the * subunit WCS and left in the buffer "wcsbuf", rather than being passed via * a text file. */ static struct ctran * wcs_update (fr) struct framebuf *fr; { register struct ctran *ct = &fr->fb_ctran; char buf[1024], *format; /* Get the new WCS. */ if (!ct->valid) { fr->fb_label[0] = '\0'; ct->zt = W_UNITARY; /* Attempt to read the WCS file and set up a unitary transformation * if the file cannot be read. */ if (sscanf (wcsbuf[fr->fb_frameno-1], "%[^\n]\n%f%f%f%f%f%f%f%f%d", buf, &ct->a, &ct->b, &ct->c, &ct->d, &ct->tx, &ct->ty, &ct->z1, &ct->z2, &ct->zt) < 7) { if (wcsbuf[fr->fb_frameno-1][0]) fprintf (stderr, "imtool: error reading WCS file\n"); strncpy (ct->imtitle, "[NO WCS]\n", SZ_IMTITLE); ct->a = ct->d = 1; ct->b = ct->c = 0; ct->tx = ct->ty = 0; ct->zt = W_UNITARY; } else strncpy (ct->imtitle, buf, SZ_IMTITLE); /* Correct for the current zoom factor, if any. */ if (fr->fb_xzoom > 1) { if (abs(ct->a) < 1.01) ct->tx += (ct->a > 0) ? -0.5 : 0.5; if (abs(ct->d) < 1.01) ct->ty += (ct->d > 0) ? -0.5 : 0.5; ct->a = ct->a / fr->fb_xzoom; ct->d = ct->d / fr->fb_xzoom; } window_set (gio_frame, FRAME_LABEL, framelabel(), 0); ct->valid++; } /* Determine best format for wcs output. */ if (ct->valid && ct->zt == W_LINEAR) { float z1, z2, zrange; z1 = ct->z1; z2 = ct->z2; zrange = (z1 > z2) ? z1 - z2 : z2 - z1; if (zrange < 100.0 && (abs(z1) + abs(z2)) / 2.0 < 200.0) format = " %7.2f %7.2f %7.3f%c"; else if (zrange > 99999.0 || (abs(z1) + abs(z2)) / 2.0 > 99999.0) format = " %7.2f %7.2f %7.3g%c"; else format = W_DEFFORMAT; } else format = " %7.2f %7.2f %7.0f%c"; strcpy (ct->format, format); return (ct); } /* SET_WCSBOXPOS -- Set the position of the WCS output box. */ static set_wcsboxpos() { /* Compute offset to coordinate output box. */ if ((wc_xoff + wc_yoff) == 0) { wc_width = wc_font->pf_defaultsize.x * 25; wc_height = wc_font->pf_defaultsize.y + 5; wc_xoff = max (0, min (Fb_width, pw_rect.r_width) - wc_width - TOOL_BORDERWIDTH); wc_yoff = max (0, pw_rect.r_height - cb_height - wc_height - TOOL_BORDERWIDTH); } } /* FRAMELABEL -- Return a pointer to the frame label string for the current * frame. */ static char * framelabel() { char fname[SZ_FNAME]; char label[SZ_LABEL*2]; sprintf (fname, o_fname, df_p->fb_frameno, df_p->fb_imageno); sprintf (label, "[%d] %s: %s", df_p->fb_frameno, fname, df_p->fb_ctran.imtitle); strncpy (df_p->fb_label, label, SZ_LABEL); return (df_p->fb_label); } /* GETFNAME -- Construct the pathname of a user datafile. One optional * integer argument is permitted. */ static char * getfname (rootname, arg) char *rootname; /* root filename (printf style format) */ int arg; { static char pathname[SZ_FNAME]; char fmt[SZ_LINE], *udir; /* Were we passed an absolute pathname as input? */ if (*rootname == '/') { strcpy (pathname, rootname); return (pathname); } if ((udir = getenv ("WCSDIR")) == NULL) if ((udir = getenv ("wcsdir")) == NULL) if ((udir = getenv ("HOME")) == NULL) udir = "/tmp"; sprintf (fmt, "%s/%s", udir, rootname); sprintf (pathname, fmt, arg); return (pathname); } /* GIO_SETCURSOR -- Set graphics frame cursor options. */ static gio_setcursor (op1, op2) int op1, op2; { Cursor cursor; int option[2], i; int blink=cursor_blink, show=cursor_show; /* Normalize the argument list. */ for (option[0]=op1, option[1]=op2, i=0; i < 2; i++) switch (option[i]) { case BLINK_OFF: case BLINK_ON: blink = option[i]; break; case CURSOR_OFF: case CURSOR_ON: show = option[i]; break; } /* Do we need to change anything? */ if (blink == cursor_blink && show == cursor_show) return; /* Modify the cursor attributes. */ if (show == CURSOR_ON && reading_imcursor) gio_readcursor (imcursor_wcs); else { cursor = window_get (gio_canvas, WIN_CURSOR); cursor_set (cursor, CURSOR_SHOW_CURSOR, FALSE, CURSOR_SHOW_CROSSHAIRS, (show == CURSOR_ON), CURSOR_CROSSHAIR_THICKNESS, 1, CURSOR_CROSSHAIR_LENGTH, 20, CURSOR_CROSSHAIR_GAP, 6, #ifdef sparc /* This is a kludge to work around a bug with the * sparcstation 1 under 4.0.3. */ CURSOR_CROSSHAIR_OP, PIX_SRC ^ PIX_DST, #else CURSOR_CROSSHAIR_OP, PIX_SRC, #endif CURSOR_CROSSHAIR_COLOR, CMS_CURSOR, 0); window_set (gio_canvas, WIN_CURSOR, cursor, 0); } cursor_blink = blink; cursor_show = show; } /* GIO_SETCURSORPOS -- Set the position of the graphics cursor within the * graphics frame. */ static gio_setcursorpos (x, y) int x, y; /* pixwin pixel coords */ { if (window_open) window_set (gio_canvas, WIN_MOUSE_XY, last_bx=x, last_by=y, 0); } /* RESET_PROC -- Called from the setup panel to reset the state of the * display. */ static reset_proc() { register struct pixrect *pr = get_screen_rect(); register struct framebuf *fb; register int i; stop_pan(); blink = 0; display_coords = 0; setup_xoff = 4; setup_yoff = 18; wc_xoff = wc_yoff = 0; state = TRACK_CURSOR; for (i=0; i < fb_nframes; i++) { fb = &frames[i]; fb->fb_xoff = 0; fb->fb_yoff = 0; fb->fb_xzoom = fb->fb_yzoom = 1; fb->fb_center = fb_ngrey / 2.0; fb->fb_slope = (float)white / (float)(fb_ngrey - 1); fb->fb_maptype = MONO; fb->fb_objno = 1; fb->fb_imageno = 0; fb->fb_frameno = i + 1; } gio_xsize = initial_gio_xsize; gio_ysize = initial_gio_ysize; gio_xsize = min (pr->pr_width - TOOL_BORDERWIDTH * 2, gio_xsize); gio_ysize = min (pr->pr_height - tool_headerheight ((int)window_get(gio_frame,FRAME_SHOW_LABEL)) - TOOL_BORDERWIDTH, gio_ysize); window_set (gio_canvas, WIN_WIDTH, gio_xsize, WIN_HEIGHT, gio_ysize, 0); window_fit (gio_canvas); window_fit (gio_frame); set_frame (1); } /* MAPRECT -- Compute the intersection of the given subrect of the first rect * with the second rect, in the coordinate system of the second. The rects * are defined in screen coordinates, the subrects relative to their parent * rects. */ maprect (r1, s1, r2, s2) BRect *r1, *s1; /* source rect and subrect */ BRect *r2, *s2; /* destination rect and subrect */ { int xoff, yoff; int x0, y0, x1, y1; /* Compute offset of second rect from the first. */ xoff = r2->r_left - r1->r_left; yoff = r2->r_top - r1->r_top; /* Translate the first subrect into the coordinate system of the * second rect. */ x0 = s1->r_left - xoff; y0 = s1->r_top - yoff; x1 = x0 + s1->r_width - 1; y1 = y0 + s1->r_height - 1; /* Does the new subrect totally miss the second rect? */ if (x1 < 0 || x0 >= r2->r_width || y1 < 0 || y0 >= r2->r_height) { *s2 = *r2; s2->r_width = s2->r_height = 0; } else { /* Clip the new subrect to the boundary of the second rect. */ if (x0 < 0) x0 = 0; else if (x0 >= r2->r_width) x0 = r2->r_width - 1; if (x1 < 0) x1 = 0; else if (x1 >= r2->r_width) x1 = r2->r_width - 1; if (y0 < 0) y0 = 0; else if (y0 >= r2->r_height) y0 = r2->r_height - 1; if (y1 < 0) y1 = 0; else if (y1 >= r2->r_height) y1 = r2->r_height - 1; /* Compute the new subrect. */ s2->r_left = x0; s2->r_top = y0; s2->r_width = x1 - x0 + 1; s2->r_height = y1 - y0 + 1; } return (s2->r_width > 0 && s2->r_height > 0); } /* BPW_GET_REGION_RECT -- Get pw_rect, transforming a Rect to a BRect. */ static Bpw_get_region_rect (pw, br) Pixwin *pw; BRect *br; { Rect r; pw_get_region_rect (pw, &r); br->r_left = r.r_left; br->r_top = r.r_top; br->r_width = r.r_width; br->r_height = r.r_height; } /* BPW_LOCK -- Lock a big pixwin. */ static Bpw_lock (pw, br) Pixwin *pw; BRect *br; { Rect r; r.r_left = br->r_left; r.r_top = br->r_top; r.r_width = br->r_width; r.r_height = br->r_height; pw_lock (pw, &r); } /* BPW_UNLOCK -- Unlock a big pixwin. */ static Bpw_unlock (pw) Pixwin *pw; { pw_unlock (pw); } /* IMAGECOPY_PROC -- Make a hardcopy of the image window on the laserwriter. * We don't do this immediately, but rather after a delay of a few milliseconds * to allow the window system to restore the imtool window lookup table after * the mouse button is released. */ static imagecopy_proc() { static Notify_value ev_screendump(); window_set (gio_frame, WIN_SHOW, TRUE, 0); imt_pause (100, ev_screendump); } /* EV_SCREENDUMP -- Called after the specified interval has passed to carry out * the actual screendump operation. */ static Notify_value ev_screendump() { int depth = 8; edit_colormap(); if (snap_frame_too) { screendump ( (int) window_get (gio_canvas, WIN_FD), win_get_pixwin (gio_canvas), (int) window_get (gio_frame, WIN_WIDTH), (int) window_get (gio_frame, WIN_HEIGHT), (int) window_get (gio_frame, WIN_X), (int) window_get (gio_frame, WIN_Y), depth); } else { screendump ( (int) window_get (gio_canvas, WIN_FD), win_get_pixwin (gio_canvas), (int) window_get (gio_frame, WIN_WIDTH) - TOOL_BORDERWIDTH * 2, (int) window_get (gio_frame, WIN_HEIGHT) - HEIGHTADJUST - cb_height, (int) window_get (gio_frame, WIN_X) + TOOL_BORDERWIDTH, (int) window_get (gio_frame, WIN_Y) + HEIGHTADJUST - TOOL_BORDERWIDTH, depth); } return (NOTIFY_DONE); } /* IMT_PAUSE -- Suspend output for the indicated number of milliseconds, to * allow other event processing to catch up. */ imt_pause (msec, ufcn) int msec; Notify_value (*ufcn)(); { static struct itimerval itimer_delay; itimer_delay.it_interval.tv_usec = 0; itimer_delay.it_interval.tv_sec = 0; itimer_delay.it_value.tv_usec = (msec % 1000) * 1000; itimer_delay.it_value.tv_sec = (msec / 1000); notify_set_itimer_func ((int)ufcn, ufcn, ITIMER_REAL, &itimer_delay, NULL); } /* PRINT_USAGE -- Print instructions on how to use this window tool. */ static print_usage (toolname) char *toolname; { printf ("no on-line help text yet for IMTOOL\n"); }