
/**********************************************************************

        MEGABLIT.C - a GEM based drawing program 1/06/89 18:00
        ------------------------------------------------------
        Skeleton of GEM application          (c) 1985 by Atari
        MEGABLIT routines   (c) 1986,87,88,89 by Darek Mihocka

        This code was first written 3 years ago when I knew
        NOTHING about programming GEM. I tried to clean it up
        but I think it's a lost case! (Did I really write code
        like these. Scary!) It's been fixed up to use embedded
        resource trees and to compile under Laser C. I didn't
        even try to fix any bugs. It's hopeless! I added in
        comments here and there, as if that'll help anyone
        decrypt this code.

**********************************************************************/

#include <obdefs.h>
#include <gemdefs.h>
#include <osbind.h>
#include <stdio.h>
#include <strings.h>
#include <fcntl.h>
#include <math.h>
#include "megablit.h"

#define TRUE 1
#define FALSE 0
#define WI_KIND  (CLOSER|NAME|VSLIDE|HSLIDE|UPARROW|DNARROW|LFARROW|RTARROW)

       /* arrow messages Megamax forgot to include!!  */
#define WA_UPPAGE 0
#define WA_DNPAGE 1
#define WA_UPLINE 2
#define WA_DNLINE 3
#define WA_LFPAGE 4
#define WA_RTPAGE 5
#define WA_LFLINE 6
#define WA_RTLINE 7

#define min(x,y)  ((x>y) ? y : x )
#define max(x,y)  ((x>y) ? x : y )
#define abs(x)    ((x<0) ?-x : x )
#define swap(x,y) { x+=y; y=x-y; x-=y; }

extern int      gl_apid;

/* bogus bindings not really needed */
int contrl[12], intin[128], ptsin[128], intout[128], ptsout[128];

int gl_wchar, gl_hchar, gl_wbox, gl_hbox;        /* system sizes */

int phys_handle;    /* physical workstation handle */
int handle;         /* virtual workstation handle */
int wi_handle;      /* window handle */
int top_window;     /* handle of topped window */

int xdesk,ydesk,hdesk,wdesk;        /* desktop area */
int xwork,ywork,hwork,wwork;        /* work area */

int msgbuff[8];     /* event message buffer */
int keycode;        /* keycode returned by event-keyboard */
int ret;            /* dummy return variables */
char dummy[4];

int work_in[11];        /* Input to GSX parameter array */
int work_out[57];       /* Output from GSX parameter array */
int pxyarray[10];       /* input point array */

/* array of pointers to trees */
extern long rs_trindex[];

/* pointers to dialog box and menu bar */
OBJECT *dialog, *menu, *fill_box, *default_box, *objTitle;

MFDB screen, copybuf, bigscreen,
    textscreen, undoscreen; /* memory definition blocks for buffers */

int rez,                /* screen mode -  0=low  1=med  2=hi */
    rscalex, rscaley, rplane, rwdwidth, rbigwidth,
    *buf, *bigbuf,      /* pointer to copy buffer, and large buffer */
    *textbuf, *undobuf,
    true_wwork, true_hwork,  /* real wwork & hwork */
    zoom_wwork, zoom_hwork,  /* what they are during zoom */
    zxwork, zywork, zwwork, zhwork, /* zoom window dimensions */
    mag_x, mag_y,       /* magnification factors during zoom */
    zbox_x, zbox_y,     /* co-ordinates of zoom box */
    zbox_w, zbox_h,     /* height of zoom box */
    SnapSize,           /* snap size in pixels */
    LineWidth,          /* line width in pixels */
    drew,               /* flag to re-draw the zoom window */
    xsize, ysize ,      /* size of total picture (should be 1024x1024) */
    xpos, ypos ,        /* position of left corner of window */
    x_undo, y_undo,     /* position when undo buffer saved */
    x, y,               /* screen co-ordinates of mouse */
    x2, y2,             /* opposite corner of rubber box */
    ox, oy,             /* original (x,y) used by LINE, etc. */
    state, but,         /* keyboard state and mouse button state */
    draw_color,         /* which of the 16 registers is being drawn with */
    draw_mode,          /* what type of drawing: line, circle, etc. */
    copy_mode,          /* 1-block  2-OR  3-XOR  4-reverse */
    fill_flag,          /* filled/unfilled polygons */
    snap_flag,          /* whether or not mouse snaps */
    dump_flag ,         /* 0-no  1-starting a new dump 2-doing a dump */
    zoom_flag,          /* sez whether we have the zoom window on */
    mdFill,             /* fill pattern 0-35 */
    mdLW,               /* line width 0-4 */
    mdSS,               /* snap size 0-4 */
    mdLS,               /* line start in pixels */
    mdLE,               /* line end in pixels */
    valid_fn,           /* if current path and filename are valid */
    block_mode ,        /* 0-off 1-getting copy block  2-copying */
    blockw, blockh,     /* width and height of block */
    maxw, maxh,         /* used by copy block routine to clip block */
    mode_table[5],      /* also used by above to select copy type */
    arr_pnts[20] ,      /* used to pass VDI an array of co-ordinates */
    Dheader[17];       /* DEGAS header */

char *path, selection[15], filename[80];   /* file I/O variables */

int palette[3][16] = {
  { 0x777, 0x700, 0x070, 0x007, 0x770, 0x463, 0x635, 0x555,
    0x333, 0x166, 0x717, 0x661, 0x400, 0x040, 0x004, 0x000 },
  { 0x777, 0x700, 0x070, 0x000, 0x000, 0x000, 0x000, 0x000,
    0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 },
  { 0x777, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
    0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 }
 };

int scalex[3] = {1,2,2};
int scaley[3] = {1,1,2};
int plane[3] = {4,2,1};
int wdwidth[3] = {20,40,40};
int bigwidth[3] = {24,48,48};

int mpLW[5] = { 1,3,5,7,9 };
int mpSS[5] = { 4,6,8,12,16 };

/****************************************************************/

open_vwork()
    {
    register int i;
    int handle;

    for(i=0;i<10;work_in[i++]=1)
        ;
    work_in[10]=2;                /* raster co-ordinates */
    handle=phys_handle;
    v_opnvwk(work_in,&handle,work_out);
    return(handle);
    }

/****************************************************************/

set_clip(x,y,w,h) int x,y,w,h; {

  int clip[4];
    clip[0]=x; clip[1]=y; clip[2]=x+w-1; clip[3]=y+h-1;
    vs_clip(handle,1,clip);
 }

/****************************************************************/

open_window(name, options, x, y, width, height, wx, wy, ww, wh)
char *name;
int options, x, y, width, height;
int *wx, *wy, *ww, *wh;
    {
    wi_handle=wind_create(options,x,y,width,height);
    wind_set(wi_handle, WF_NAME,name,0,0);
    graf_growbox(x+width/2,y+height/2,
      gl_wbox,gl_hbox,x,y,width,height);
    wind_open(wi_handle,x,y,width,height);
    wind_get(wi_handle,WF_WORKXYWH,wx,wy,ww,wh);

    return(wi_handle);
    }

/****************************************************************/

do_redraw(xc,yc,wc,hc)
int xc,yc,wc,hc;
  {
  GRECT t1,t2;

  graf_mouse(M_OFF,0L);
  wind_update(TRUE);
  t2.g_x=xc; t2.g_y=yc; t2.g_w=wc; t2.g_h=hc;

  wind_get(wi_handle,WF_FIRSTXYWH,&t1.g_x,&t1.g_y,&t1.g_w,&t1.g_h);
  while (t1.g_w && t1.g_h) {
    if (rc_intersect(&t2,&t1)) {
      set_clip(t1.g_x,t1.g_y,t1.g_w,t1.g_h);
      buf_to_scr (t1.g_x-xwork, t1.g_y-ywork, t1.g_w, t1.g_h);
     }
    wind_get(wi_handle,WF_NEXTXYWH,&t1.g_x,&t1.g_y,&t1.g_w,&t1.g_h);
   }
  if (zoom_flag) do_zoom();
  set_clip(xwork,ywork,wwork,hwork);
  wind_update(FALSE);
  graf_mouse(M_ON,0L);
  }

/****************************************************************/

do_dialog(dialog)
register OBJECT *dialog;
   {
   int cx, cy, cw, ch, xc, yc, msg;

   form_center(dialog, &cx, &cy, &cw, &ch);
   scr_to_buf(cx-xwork,cy-ywork,cw+4,ch+4);      /* buffer the box */
   xc = cx + cw/2;
   yc = cy + ch/2;
   form_dial(FMD_START, cx, cy, cw, ch, cx, cy, cw, ch);
   form_dial(FMD_GROW, xc,yc,0,0, cx, cy, cw, ch);
   objc_draw(dialog, 0, 10, cx, cy, cw, ch);
   msg = form_do(dialog, 0);
   form_dial(FMD_SHRINK, xc,yc,0,0, cx, cy, cw, ch);
   form_dial(FMD_FINISH, 0,0,0,0, cx, cy, cw, ch);
   buf_to_scr(cx-xwork,cy-ywork,cw+4,ch+4);      /* unbuffer the box */
   return(msg);
   }

/*****************************************************************
** init resource, allocate memory, initialize screen, and paint **
*****************************************************************/

main()
  {
  register long memfree;
  register int xpix, ypix;

  appl_init();

  rez=Getrez();
  rscalex=scalex[rez];
  rscaley=scaley[rez];
  rplane=plane[rez];
  rwdwidth=wdwidth[rez];
  rbigwidth=bigwidth[rez];

#ifdef NEVER
  if (!rsrc_load("megablit.rsc")) {      /* load MEGABLIT.RSC file */
    form_alert(1,"[0][ | no RCS |  file  | ][ oh ya! ]");
    exit(0);
   }
#else
    rsc_fix();
#endif

  buf = (int *) Malloc(32000L);       /* allocate copy buffer */
  undobuf = (int *) Malloc(32000L);       /* allocate undo buffer */
  memfree = Malloc(-1L);
  if (memfree<=60000L) {
    form_alert(1,"[0][  |  Out of  |  Memory  |  ][ aack!! ]");
    exit(0);
   }

    /* I've completely forgotten how this allocation of the buffer
       is supposed to work, but somehow it does! */

  xpix=1;
  ypix=1;        /* 320*200 or 640*400 */

  if (memfree>=100000L)
      xpix *=2;  /* a 64K screen - 640*200 or 1280*400*/
  if (memfree>= 200000L)
      ypix *=2; /* a 128K screen - 640*400 or 1280*800 */
  if (memfree>= 400000L)
      xpix *=2; /* a 256K screen - 1280*400 or 2560*800 */
  if (memfree>= 800000L)
      ypix *=2; /* a 512K screen - 1280*800 or 2560*1600*/

  /* size of MEGABLIT drawing area */
  xsize=384*xpix*rscalex; ysize=256*ypix*rscaley;

  bigbuf = (int *) Malloc((long)xsize*(long)ysize/8L*(long)rplane);

  graf_mouse(M_OFF,0L);
  graf_mouse(OUTLN_CROSS,0L);

  bigscreen.fd_addr = (long) bigbuf;   /* FDB for virtual screen */
  bigscreen.fd_w = xsize;              /* virtual screen size */
  bigscreen.fd_h = ysize;
  bigscreen.fd_wdwidth = rbigwidth*xpix;  /* # of integers in one line */
  bigscreen.fd_stand = 0;              /* pixel co-ordinates */
  bigscreen.fd_nplanes = rplane;            /* # of bit planes */

  screen.fd_addr = Physbase();         /* FDB for desktop */
  screen.fd_w = 320*xpix*rscalex;
  screen.fd_h = 200*ypix*rscaley;
  screen.fd_wdwidth = rwdwidth;
  screen.fd_stand = 0;
  screen.fd_nplanes = rplane;

  copybuf.fd_addr = (long) buf;        /* FDB for copy buffer */
  copybuf.fd_w = 320*xpix*rscalex;  copybuf.fd_h = 200*ypix*rscaley;
  copybuf.fd_wdwidth = rwdwidth; copybuf.fd_stand = 0;
  copybuf.fd_nplanes = rplane;

  undoscreen.fd_addr = (long) undobuf;        /* FDB for undo buffer */
  undoscreen.fd_w = 320*ypix*rscalex; undoscreen.fd_h = 200*ypix*rscaley;
  undoscreen.fd_wdwidth = rwdwidth;  undoscreen.fd_stand = 0;
  undoscreen.fd_nplanes = rplane;

  path = "A:\\*.PI1\000\000\000\000\000                                                       ";
  path[0] = 'A' + Dgetdrv();
  path[7] = rez + '1';
  selection[0] = 0;
  valid_fn = FALSE;

#ifdef NEVER
  rsrc_gaddr(0, DEFAULTS, &default_box);
  rsrc_gaddr(0, FILLS, &fill_box);
  rsrc_gaddr(0, MAIN_BAR, &menu);
#else
  menu = (OBJECT *) rs_trindex[MAIN_BAR];
  fill_box = (OBJECT *) rs_trindex[FILLS];
  default_box = (OBJECT *) rs_trindex[DEFAULTS];
  objTitle = (OBJECT *) rs_trindex[TITLE];
#endif

  menu_bar (menu,TRUE);

  phys_handle=graf_handle(&gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox);
  wind_get(0, WF_WORKXYWH, &xdesk, &ydesk, &wdesk, &hdesk);
  handle = open_vwork();
  open_window(" no name ", WI_KIND, xdesk, ydesk, wdesk, hdesk,
                   &xwork, &ywork, &wwork, &hwork );

  mode_table[1] = 3;  /* conversion between the 16 copy types to 4 */
  mode_table[2] = 7;
  mode_table[3] = 6;
  mode_table[4] = 8;

  true_wwork = wwork;  true_hwork = hwork;
  zoom_wwork = wwork/2;  zoom_hwork = hwork;
  zbox_w = zbox_h = 16;  /* 16*16 zoom box */

  draw_color = 1;      /* black */
  menu[COLOR1].ob_state |= CHECKED;     /* initialize BLACK checkmark */
  set_color(draw_color);
  copy_mode = 1;        /* destructive draw */
  menu[REPLACE].ob_state ^= CHECKED;   /* initialize REPLACE checkmark */
  snap_flag = fill_flag = FALSE;
  draw_mode = DRAW;
  menu[draw_mode].ob_state ^= CHECKED; /* initialize DRAW checkmark */
  zoom_flag = FALSE;
  menu[ZOOM].ob_state &= ~CHECKED;
  vswr_mode(handle,copy_mode);
  vsf_perimeter(handle,0);

  clear_work();         /* clear out work area and initialize position */

  /* disable cursor */

  graf_mouse(ARROW,0L);
  graf_mouse(M_ON,0L);

  do_dialog(objTitle);  /* show title... */

  multi();           /* ... and paint!! */

  /* enable cursor */

  wind_close(wi_handle);
  graf_shrinkbox(xwork+wwork/2,ywork+hwork/2,
  gl_wbox,gl_hbox,xwork,ywork,wwork,hwork);
  wind_delete(wi_handle);
  menu_bar (menu,FALSE);
  v_clsvwk(handle);

  Mfree(bigbuf);           /* give memory back to nice operating system */
  Mfree(buf);
  appl_exit();              /* bye bye */
  }

/*****************************************************************
** anything that ever happens goes through the multi() routine  **
*****************************************************************/

multi()
  {
  register int event, quit=0;

      do
        {

        event = evnt_multi(MU_MESAG | MU_BUTTON | MU_KEYBD,
                        1,1,TRUE , 0,0,0,0,0, 0,0,0,0,0,
                        msgbuff,0,0,&x,&y,&but,&state,&keycode,&ret);

        if (snap_flag)
                snap (&x,&y);
        drew = FALSE;         /* modified zoom window flag */

        wind_update(TRUE);

        if (event & MU_KEYBD)
           {
           keycode = (keycode>>8)&0x00FF;
           if (keycode==0x61)
               undo_to_scr();
           else if (keycode==0x62)
               do_dialog(objTitle);;
           }

        else if (event & MU_MESAG) {
          switch (msgbuff[0]) {

          case MN_SELECTED:
            switch(msgbuff[3]) {

              case DESK:
                do_dialog(objTitle);;
                menu_tnormal(menu,DESK,1);
                break;

              case FILE:
                switch (msgbuff[4]) {

                  case M_LOAD:
                    if (get_fn())
                        load_file(filename);
                    break;

                  case M_SAVE:
                    valid_fn = get_fn();
                    if (!valid_fn) break;
                  case M_UPDATE:
                    if (valid_fn)
                        save_file(filename);
                    else
                      form_alert(1,
                      "[0][  |  Currently  |  untitled!  |  ][ forgot! ]");
                    break;

                  case M_QUIT:
                    quit = 2 - form_alert(1,
                      "[0][  |   Leaving???    |  ][ Yes | No ]");
                    break;

                  case M_NEW:
                    if (1== (form_alert(1,
                      "[0][ |    Start    |   fresh??   | ][ Yes | No! ]")))
                        clear_work();
                    break;
                 }
                menu_tnormal(menu,FILE,1);
                break;

              case OPTIONS:
                {
                int selection;
                selection=msgbuff[4];

                switch (selection)
                  {
                  case ZOOM_IN:
                    if (zoom_flag && zbox_w>4) {
                      zbox_w /= 2;
                      zbox_h /= 2;
                      drew=TRUE;
                     }
                    break;

                  case ZOOM_OUT:
                    if (zoom_flag && zbox_w<64) {
                      zbox_w *= 2;
                      zbox_h *= 2;
                      drew=TRUE;
                     }
                    break;

                  case OPT_FILL:
                        select_fill();
                        break;

                  case OPT_OTHR:
                        select_other();
                        break;

                  default:

                    if (rez==2 && selection!=COLOR0 && selection!=COLOR1)
                        break;
                    if (rez==1 && selection!=COLOR0 && selection!=COLOR1
                               && selection!=COLOR2 && selection!=COLOR3)
                        break;
                    menu[COLOR0].ob_state &= ~CHECKED;
                    menu[COLOR1].ob_state &= ~CHECKED;
                    menu[COLOR2].ob_state &= ~CHECKED;
                    menu[COLOR3].ob_state &= ~CHECKED;
                    menu[COLOR4].ob_state &= ~CHECKED;
                    menu[COLOR5].ob_state &= ~CHECKED;
                    menu[COLOR6].ob_state &= ~CHECKED;
                    menu[COLOR7].ob_state &= ~CHECKED;
                    menu[COLOR8].ob_state &= ~CHECKED;
                    menu[COLOR9].ob_state &= ~CHECKED;
                    menu[COLORA].ob_state &= ~CHECKED;
                    menu[COLORB].ob_state &= ~CHECKED;
                    menu[COLORC].ob_state &= ~CHECKED;
                    menu[COLORD].ob_state &= ~CHECKED;
                    menu[COLORE].ob_state &= ~CHECKED;
                    menu[COLORF].ob_state &= ~CHECKED;
                    menu[selection].ob_state |= CHECKED;

    /* This is NOT the way to do this. Simply sorting the object and
       doing
            draw_color = selection - COLOR0;
       would have worked!
    */
                    switch (selection)
                        {
                    case COLOR0:
                        draw_color = 0;
                        break;
                    case COLOR1:
                        draw_color = 1;
                        break;
                    case COLOR2:
                        draw_color = 2;
                        break;
                    case COLOR3:
                        draw_color = 3;
                        break;
                    case COLOR4:
                        draw_color = 4;
                        break;
                    case COLOR5:
                        draw_color = 5;
                        break;
                    case COLOR6:
                        draw_color = 6;
                        break;
                    case COLOR7:
                        draw_color = 7;
                        break;
                    case COLOR8:
                        draw_color = 8;
                        break;
                    case COLOR9:
                        draw_color = 9;
                        break;
                    case COLORA:
                        draw_color = 0xA;
                        break;
                    case COLORB:
                        draw_color = 0xB;
                        break;
                    case COLORC:
                        draw_color = 0xC;
                        break;
                    case COLORD:
                        draw_color = 0xD;
                        break;
                    case COLORE:
                        draw_color = 0xE;
                        break;
                    case COLORF:
                        draw_color = 0xF;
                        break;
                        }
                    set_color(draw_color);
                    break;
                  }
                  menu_tnormal(menu,OPTIONS,1);
               }

              case MODE:
                switch (msgbuff[4]) {

                  case POINT:
                  case DRAW:
                  case LINE:
                  case RAY:
                  case BOX:
                  case ARC:
                  case PIE:
                  case ELLIPSE:
                  case RND_BOX:
                  case POLYGON:
                    menu[draw_mode].ob_state ^= CHECKED;
                    draw_mode = msgbuff[4];
                    menu[draw_mode].ob_state ^= CHECKED;
                    block_mode = 0;     /* de-activate block_mode */
                    menu[COPY].ob_state &= ~CHECKED;
                    menu[MARK].ob_state &= ~CHECKED;
                    menu[DELETE].ob_state &= ~CHECKED;
                    break;

                  case FILL:
                    menu[FILLFLAG].ob_state ^= CHECKED;
                    fill_flag ^= TRUE;
                    break;

                  case SNAP:
                    menu[SNAPFLAG].ob_state ^= CHECKED;
                    snap_flag ^= TRUE;
                    break;

                  case REPLACE:
                    copy_mode = 1;
                    menu[REPLACE].ob_state |= CHECKED;
                    menu[TRANSP].ob_state &= ~CHECKED;
                    menu[XOR].ob_state &= ~CHECKED;
                    menu[INVERSE].ob_state &= ~CHECKED;
                    break;

                  case TRANSP:
                    copy_mode = 2;
                    menu[REPLACE].ob_state &= ~CHECKED;
                    menu[TRANSP].ob_state |= CHECKED;
                    menu[XOR].ob_state &= ~CHECKED;
                    menu[INVERSE].ob_state &= ~CHECKED;
                    break;

                  case XOR:
                    copy_mode = 3;
                    menu[REPLACE].ob_state &= ~CHECKED;
                    menu[TRANSP].ob_state &= ~CHECKED;
                    menu[XOR].ob_state |= CHECKED;
                    menu[INVERSE].ob_state &= ~CHECKED;
                    break;

                  case INVERSE:
                    copy_mode = 4;
                    menu[REPLACE].ob_state &= ~CHECKED;
                    menu[TRANSP].ob_state &= ~CHECKED;
                    menu[XOR].ob_state &= ~CHECKED;
                    menu[INVERSE].ob_state |= CHECKED;
                    break;

                  case MARK:
                    block_mode = 1;
                    menu[MARK].ob_state |= CHECKED;
                    menu[COPY].ob_state &= ~CHECKED;
                    menu[DELETE].ob_state &= ~CHECKED;
                    break;

                  case COPY:
                    block_mode = (blockh+blockw) ? 2 : 0;
                    menu[COPY].ob_state &= ~CHECKED;
                    menu[MARK].ob_state &= ~CHECKED;
                    menu[DELETE].ob_state &= ~CHECKED;
                    if (block_mode) menu[COPY].ob_state |= CHECKED;
                    break;

                  case DELETE:
                    block_mode = 3;
                    menu[MARK].ob_state &= ~CHECKED;
                    menu[COPY].ob_state &= ~CHECKED;
                    menu[DELETE].ob_state |=CHECKED;
                    break;

                  case ZOOM:
                    menu[ZOOMFLAG].ob_state ^= CHECKED;
                    zoom_flag ^= TRUE;
                    if (zoom_flag) {
                      scr_to_buf(0,0,wwork,hwork);
                      wwork = zoom_wwork;
                      hwork = zoom_hwork;
                      buf_to_scr(0,0,wwork,hwork);
                      update_slider(1,1);
                      update_slider(-1,-1);

                      drew=FALSE;
                     }
                    else {
                      scr_to_buf(0,0,wwork,hwork);
                      wwork = true_wwork;
                      hwork = true_hwork;
                      buf_to_scr(0,0,wwork,hwork);
                      update_slider(1,1);
                      update_slider(-1,-1);
                     }
                    break;

                 case UNDO:
                    undo_to_scr();
                    break;

                  }
                menu_tnormal(menu,MODE,1);
                break;

             }

          case WM_REDRAW:
            do_redraw(msgbuff[4],msgbuff[5],msgbuff[6],msgbuff[7]);
            break;

          case WM_NEWTOP:
          case WM_TOPPED:
            scr_to_buf(0,0,wwork,hwork);
            wind_set(wi_handle,WF_TOP,0,0,0,0);
            break;

          case WM_CLOSED:
            quit++;
            break;

          case WM_VSLID:
            update_slider(0,  /*dx=0*/
              (int)((long)msgbuff[4]*((long)(ysize-hwork))/1000L)-ypos);
            break;

          case WM_HSLID:
            update_slider(
              (int)((long)msgbuff[4]*((long)(xsize-wwork))/1000L)-xpos,0);
            break;

          case WM_ARROWED:
            drew = TRUE;
            switch(msgbuff[4]) {

              case WA_UPPAGE:
                  update_slider(0,-hwork/2);
                break;

              case WA_DNPAGE:
                  update_slider(0,hwork/2);
                break;

              case WA_LFPAGE:
                  update_slider(-wwork/2,0);
                break;

              case WA_RTPAGE:
                  update_slider(wwork/2,0);
                break;

              case WA_UPLINE:
                update_slider(0,-8);
                break;

              case WA_DNLINE:
                update_slider(0,8);
                break;

              case WA_LFLINE:
                update_slider(-8,0);
                break;

              case WA_RTLINE:
                update_slider(8,0);
                break;

             } /* switch (msgbuff[4]) */

           } /* switch (msgbuff[0]) */
          if (!fill_flag)
            graf_mouse(OUTLN_CROSS,0L);    /* restore crosshairs */
          else
            graf_mouse(THICK_CROSS,0L);
         }
        else {

           drew = TRUE;
           vswr_mode(handle,copy_mode);   /* go to proper blitting mode */
           scr_to_undo();                 /* UNDO wasn't picked, so update */

           if (zoom_flag && x>= zxwork)    /* if inside zoom box... */
            {
             int zx, zy, ar[4], z, ozx = -1, ozy = -1, sel=FALSE;

             do {
               zx = (x-zxwork-2);
               zy = (y-zywork-2);
               if (zx%mag_x || zy%mag_y) /* null zones between big pixels */
                 {
                 zx /= mag_x; zy /= mag_y;
                 if (zx>=0 && zx<zbox_w && zy>=0 && zy<zbox_h
                     && (zx+zy)!=(ozx+ozy))
                   {
                     ozx = zx; ozy = zy;
                     if (!sel) {             /* if zoom color not picked yet */
                       v_get_pixel (handle,zbox_x+zx,zbox_y+zy,&z,&z);
                       sel = TRUE;
                      }
                     vsf_interior(handle,1);
                     if (rez==2)
                       vsf_color(handle,1-z);   /* reverse color in mono*/
                     else
                       vsf_color(handle,draw_color);
                     ar[0] = ar[2] = zbox_x+zx;
                     ar[1] = ar[3] = zbox_y+zy;
                     v_bar(handle,ar);           /* small pixel */
                     update_zoom(zx,zy,zx+1,zy+1);
                   }
                }
               wait_mouse(&x,&y,&but);
              } while (but);
             drew = FALSE;     /* no need to redraw again */
            }
           else                            /* if not, proceed normally */
           if (!block_mode && but) switch(draw_mode)
             {
             case DRAW:
             case POINT:
               ox = x;
               oy = y;
               if (!fill_flag || draw_mode==DRAW ) {
                do {
                 arr_pnts[0] = ox;
                 arr_pnts[2] = x;
                 arr_pnts[1] = oy;
                 arr_pnts[3] = y;
                 graf_mouse(M_OFF,0L);
                 v_pline(handle,2,arr_pnts);
                 if (zoom_flag) {          /* if zoom is on, then check */
                   int zx, zy;            /* if we passed through zoom */
                   zx = (x-zbox_x);       /* window */
                   zy = (y-zbox_y);
                   if (zx>=0 && zx<zbox_w && zy>=0 && zy<zbox_h)
                      update_zoom(zx,zy,zx+1,zy+1);
                   }
                 graf_mouse(M_ON,0L);
                 ox = x;
                 oy = y;
                 wait_mouse(&x,&y,&but);
                 } while (but && draw_mode==DRAW);
                drew=FALSE;
               }
              else
                {
                graf_mouse(M_OFF,0L);
                vsf_interior(handle,(mdFill>24)?3:2);
                vsf_style(handle,mdFill%24);
                vsf_color(handle,draw_color);
                v_contourfill(handle,x,y,-1);
                graf_mouse(M_ON,0L);
                }
              break;

             case LINE:
               ox = x; oy = y;
               rubber_shape(LINE,ox,oy,&x2,&y2);
               graf_mouse(M_OFF,0L);
               vsl_ends(handle,mdLS,mdLE);
               vsl_width(handle,LineWidth);
               v_pline(handle,2,arr_pnts);
               graf_mouse(M_ON,0L);
             break;

             case POLYGON:
              {
               int points=1, ar[40];

               ar[0] = x2 = x;
               ar[1] = y2 = y;
               do {
                 ox = x2; oy = y2;
                 rubber_shape(LINE,ox,oy,&x2,&y2);
                 graf_mouse(M_OFF,0L);
                 v_pline(handle,2,arr_pnts);
                 graf_mouse(M_ON,0L);
                 ar[points*2] = x2;
                 ar[points*2+1] = y2;
                 points++;
                } while (x2!=ox || y2!=oy);
               if (fill_flag)
                 {
                 graf_mouse(M_OFF,0L);
                 v_fillarea(handle,points,ar);
                 graf_mouse(M_ON,0L);
                 }
              }
             break;

             case RAY:
               arr_pnts[0] = x;
               arr_pnts[1] = y;
               do {
                 arr_pnts[2] = x;
                 arr_pnts[3] = y;
                 graf_mouse(M_OFF,0L);
                 vsl_ends(handle,mdLS,mdLE);
                 vsl_width(handle,LineWidth);
                 v_pline(handle,2,arr_pnts);
                 graf_mouse(M_ON,0L);
                 wait_mouse(&x,&y,&but);
                } while (but);
               break;

             case BOX:
                rubber_shape(BOX,x,y,&x2,&y2);
                graf_mouse(M_OFF,0L);
                vsl_ends(handle,0,0);
                vsl_width(handle,LineWidth);
                if (fill_flag) {
                  arr_pnts[0] = x; arr_pnts[1] = y;
                  arr_pnts[2] = x2; arr_pnts[3] = y2;
                  v_bar(handle,arr_pnts);      /* fill in the interior */
                 }
                else v_pline(handle,5,arr_pnts);
                graf_mouse(M_ON,0L);
                break;

             case ELLIPSE:
                rubber_shape(ELLIPSE,x,y,&x2,&y2);
                graf_mouse(M_OFF,0L);
                if (fill_flag)
                  v_ellipse(handle,(x+x2)/2,(y+y2)/2,(x2-x)/2,(y2-y)/2);
                else
                  v_ellarc(handle,(x+x2)/2,(y+y2)/2,(x2-x)/2,(y2-y)/2,0,3595);
                graf_mouse(M_ON,0L);
                break;

             case RND_BOX:
                rubber_shape(BOX,x,y,&x2,&y2);
                arr_pnts[0] = x; arr_pnts[1] = y;
                arr_pnts[2] = x2; arr_pnts[3] = y2;
                graf_mouse(M_OFF,0L);
                if (fill_flag) v_rfbox(handle,arr_pnts);
                else v_rbox(handle,arr_pnts);
                graf_mouse(M_ON,0L);
                break;

             case ARC:
             case PIE:
                {
                int xx, yy, rr, ang1, ang2, ang3, txx, tyy, tang1, tang3, trr;
                vq_mouse(handle,&but,&x,&y);
                if (!but) break;
                if (snap_flag)
                     snap (&x,&y);
                rubber_shape(LINE,x,y,&x2,&y2);
                ox = x; oy = y;
                txx = tyy = trr = tang1 = tang3 = 0;
                evnt_mouse(1,x,y,1,1,&x,&y,&but,&state);
                graf_mouse(POINT_HAND,0L);  /* do a pointed hand for arc */
                vswr_mode(handle,3);
                do
                  {                    /* draw arcs when button up */
                  pts_to_arc(ox,oy,x,y,x2,y2,&xx,&yy,&rr);
                  ang1 =  calc_angle(xx,yy,ox,oy);
                  ang2 =  calc_angle(xx,yy,x,y);
                  ang3 =  calc_angle(xx,yy,x2,y2);
                  if (ang2<ang1) ang2 += 3600;
                  if (ang3<ang1) ang3 += 3600;
                  if (ang3<ang2) swap (ang1,ang3);
                  graf_mouse(M_OFF,0L);
                  if (draw_mode==ARC)
                    {
                    v_arc(handle,txx,tyy,trr,tang1,tang3);
                    v_arc(handle,xx,yy,rr,ang1,ang3);
                    }
                  else
                    {
                    v_pieslice(handle,txx,tyy,trr,tang1,tang3);
                    v_pieslice(handle,xx,yy,rr,ang1,ang3);
                    }
                  txx=xx; tyy=yy; trr=rr; tang1=ang1; tang3=ang3;
                  graf_mouse(M_ON,0L);
                  wait_mouse(&x,&y,&but);
                  } while (!but);
                graf_mouse(M_OFF,0L);
                do
                  {                    /* press button to exit */
                  vq_mouse(handle,&but,&x,&y);
                  } while (but);
                graf_mouse(M_ON,0L);
                vswr_mode(handle,copy_mode);
                }
                break;

              }  /* switch(draw_mode) */
           else
             {                      /* block mode is on */
             if (block_mode==1)
                {                /* get a new block */
                rubber_shape(BOX,x,y,&x2,&y2);
                if (x2<x) swap(x,x2);
                if (y2<y) swap(y,y2);
                blockw = x2-x; blockh = y2-y;
                arr_pnts[0] = x; arr_pnts[1] = y;
                arr_pnts[2] = x2; arr_pnts[3] = y2;
                arr_pnts[4] = 0; arr_pnts[5] = 0;
                arr_pnts[6] = blockw; arr_pnts[7] = blockh;
                graf_mouse(M_OFF,0L);
                vro_cpyfm(handle,3,arr_pnts,&screen,&copybuf);
                graf_mouse(M_ON,0L);
                }
             else if (block_mode==2)             /* copy */
                {
                do {
                  arr_pnts[0] = 0; arr_pnts[1] = 0;
                  maxw = xwork+wwork-x-1;
                  maxh = ywork+hwork-y-1;
                  if (maxw>blockw) maxw=blockw;
                  if (maxh>blockh) maxh=blockh;
                  arr_pnts[2] = maxw; arr_pnts[3] = maxh;
                  arr_pnts[4] = max(x,xwork); arr_pnts[5] = max(y,ywork);
                  arr_pnts[6] = max(x,xwork)+maxw;
                  arr_pnts[7] = max(y,ywork)+maxh;
                  if ((maxw>0) && (maxh>0))
                    {
                    graf_mouse(M_OFF,0L);
                    vro_cpyfm(handle,mode_table[copy_mode],
                        arr_pnts,&copybuf,&screen);
                    graf_mouse(M_ON,0L);
                    }
                  wait_mouse(&x,&y,&but);
                  } while(but);
                } /* if mark or copy */
             else if (block_mode==3)
                {                /* delete a new block */
                int blockw, blockh;

                rubber_shape(BOX,x,y,&x2,&y2);
                if (x2<x) swap(x,x2);
                if (y2<y) swap(y,y2);
                blockw = x2-x; blockh = y2-y;
                arr_pnts[4] = arr_pnts[0] = x;
                arr_pnts[5] = arr_pnts[1] = y;
                arr_pnts[6] = arr_pnts[2] = x2;
                arr_pnts[7] = arr_pnts[3] = y2;
                graf_mouse(M_OFF,0L);
                vro_cpyfm(handle,0,arr_pnts,&screen,&screen);
                graf_mouse(M_ON,0L);
                }
            } /* if block mode */
        } /* if menu message */

       if (zoom_flag && drew) update_zoom(0,0,zbox_w,zbox_h);

       wind_update(FALSE);

      } while(!quit);

}

/****************************************************************/

scr_to_buf(ox,oy,sx,sy)
register int ox,oy,sx,sy;
  {
  int ar[8];

  ar[0] = xwork+ox;
  ar[1] = ywork+oy;
  ar[2] = xwork+ox+sx-1;
  ar[3] = ywork+oy+sy-1;
  ar[4] = xpos+ox;
  ar[5] = ypos+oy;
  ar[6] = xpos+ox+sx-1;
  ar[7] = ypos+oy+sy-1;
  graf_mouse(M_OFF,0L);
  vro_cpyfm(handle,3,ar,&screen,&bigscreen);
  graf_mouse(M_ON,0L);
  }

/****************************************************************/

buf_to_scr(ox,oy,sx,sy)
int ox,oy,sx,sy; 
  {
  int ar[8];

  ar[0] = xpos+ox;
  ar[1] = ypos+oy;
  ar[2] = xpos+ox+sx-1;
  ar[3] = ypos+oy+sy-1;
  ar[4] = xwork+ox;
  ar[5] = ywork+oy;
  ar[6] = xwork+ox+sx-1;
  ar[7] = ywork+oy+sy-1;
  graf_mouse(M_OFF,0L);
  vro_cpyfm(handle,3,ar,&bigscreen,&screen);
  graf_mouse(M_ON,0L);
  }

/****************************************************************/

scr_to_undo()
  {
  register long *qscr=(long *)screen.fd_addr, *qundo=(long *)undobuf;
  register int cl16=2000-1-110;

  graf_mouse(M_OFF,0L);
  asm {
    lea    1760(qscr),qscr
 loop1:
    move.l (qscr)+,(qundo)+
    move.l (qscr)+,(qundo)+
    move.l (qscr)+,(qundo)+
    move.l (qscr)+,(qundo)+
    dbf    cl16,loop1
    }
  graf_mouse(M_ON,0L);

  x_undo = xpos;
  y_undo = ypos;
  }

/****************************************************************/

undo_to_scr() {

  register long *qscr=(long *)screen.fd_addr, *qundo=(long *)undobuf;
  register int cl16=2000-1-110;

  graf_mouse(M_OFF,0L);
  asm {
    lea    1760(qscr),qscr
 loop2:
    move.l (qundo)+,(qscr)+
    move.l (qundo)+,(qscr)+
    move.l (qundo)+,(qscr)+
    move.l (qundo)+,(qscr)+
    dbf    cl16,loop2
    }
  graf_mouse(M_ON,0L);
  xpos = x_undo;
  ypos = y_undo;
}

/****************************************************************/

update_slider(dx,dy)
int dx,dy;
  {      /* scroll window dx,dy pixels */
  register long xslide, yslide, xsiz, ysiz;
  int curx, cury;
  char text[80];

  scr_to_buf(0,0,wwork,hwork);
                                                /* clip scrolling */
  xpos = max(0,xpos+dx); ypos = max(0,ypos+dy);
  xpos = min(xsize-wwork,xpos);
  ypos = min(ysize-hwork,ypos);

  xsiz = (1000L * (long)wwork) / (long)xsize;
  ysiz = (1000L * (long)hwork) / (long)ysize;
  xslide = (1000L * (long)xpos) / (long)(xsize-wwork);
  yslide = (1000L * (long)ypos) / (long)(ysize-hwork);

  wind_get(wi_handle,WF_HSLIDE,&curx,dummy,dummy,dummy);
  wind_get(wi_handle,WF_VSLIDE,&cury,dummy,dummy,dummy);

  if ((int)xslide != curx) {
    wind_set(wi_handle,WF_HSLSIZE,(int)xsiz,0,0,0);
    wind_set(wi_handle,WF_HSLIDE,(int)xslide,0,0,0);
   }

  if ((int)yslide != cury) {
    wind_set(wi_handle,WF_VSLSIZE,(int)ysiz,0,0,0);
    wind_set(wi_handle,WF_VSLIDE,(int)yslide,0,0,0);
   }

  buf_to_scr(0,0,wwork,hwork);

  set_clip (xdesk,ydesk,wdesk,hdesk);
  vswr_mode(handle,1);              /* replace mode when printing */
  sprintf (text,"(%3d,%3d)", xpos-xsize/2, ypos-ysize/2);
  v_gtext(handle,xwork+4*gl_wchar,ydesk+gl_hchar-2,text);
  sprintf (text,"(%4d,%4d)", xpos+wwork-1-xsize/2, ypos+hwork-1-ysize/2);
  v_gtext(handle,xwork+true_wwork-11*gl_wchar,ydesk+gl_hchar-2,text);
  set_clip(xwork,ywork,wwork,hwork);

  drew = TRUE;
  }

/****************************************************************/

get_fn()
  {
  register int but, tp;
  int stat;

  scr_to_buf(0,0,wwork, hwork);
  fsel_input(path, selection, &stat);
  buf_to_scr(0,0,wwork, hwork);

  strcpy (filename,path);
  tp = strlen(filename);
  while (filename[tp]!='\\' && tp>0) --tp;
  strcpy (&filename[tp+1],selection);

  return stat;
  }

/****************************************************************/

load_file(fn)
char *fn;
  {
  register int fhand, stat;
  int ar[8];

  if ((fhand = Fopen(fn,O_RDONLY))<0) goto err_close;
  if ((stat=Fread (fhand,34L,&Dheader[0]))<0) goto err_close;
  if ((stat=Fread (fhand,32000L,buf))<0) goto err_close;
  Fclose (fhand);
  valid_fn = TRUE;

  if (xpos>xsize-wwork) xpos = xsize-wwork;
  if (ypos>ysize-hwork) ypos = ysize-hwork;

  ar[0] = 0;        /* copy file from copy buffer to big screen buffer */
  ar[1] = 0;
  ar[2] = 320*rscalex-1;
  ar[3] = 200*rscaley-1;
  ar[4] = xpos;
  ar[5] = ypos;
  ar[6] = xpos+320*rscalex-1;
  ar[7] = ypos+200*rscaley-1;
  graf_mouse(M_OFF,0L);
  vro_cpyfm(handle,mode_table[copy_mode],ar,&copybuf,&bigscreen);
  buf_to_scr(0,0,wwork,hwork);         /* and update window display */
  Setpalette(&Dheader[1]);
  blockh = blockw = 0;
  wind_set(wi_handle, WF_NAME,fn,0,0);
  graf_mouse(M_ON,0L);
  return(0);

 err_close:
  Fclose (fhand);
  form_alert(1,"[0][  |   Error   |  loading  |  picture  |  ][ darn ]");
  }

/****************************************************************/

save_file(fn)
char* fn;
  {
  register int fhand, stat;
  int ar[8];
  register int cc;

  for (cc=0; cc<16; cc++)
        Dheader[cc+1]= Setcolor(cc,-1);

  graf_mouse(M_OFF,0L);
  scr_to_buf(0,0,wwork,hwork);         /* save screen to big buffer */

  if (xpos>xsize-wwork) xpos = xsize-wwork;  /* then make sure picture fits */
  if (ypos>ysize-hwork) ypos = ysize-hwork;

  ar[4] = 0;        /* copy file from big screen buffer to copy buffer */
  ar[5] = 0;
  ar[6] = 320*rscalex-1;
  ar[7] = 200*rscaley-1;
  ar[0] = xpos;
  ar[1] = ypos;
  ar[2] = xpos+320*rscalex-1;
  ar[3] = ypos+200*rscaley-1;

  Dheader[0] = Getrez();

  vro_cpyfm(handle,3,ar,&bigscreen,&copybuf);
  buf_to_scr(0,0,wwork,hwork);         /* and update window display */
  graf_mouse(M_ON,0L);

  if ((fhand = Fcreate(fn,0))<0) goto err_close2;
  if ((stat=Fwrite (fhand,34L,&Dheader[0]))<0) goto err_close2;
  if ((stat=Fwrite (fhand,32000L,buf))<0) goto err_close2;
  Fclose (fhand);
  valid_fn = TRUE;

  return(0);

 err_close2:
  Fclose (fhand);
  form_alert(1,"[0][  |  error  | writing | picture |  ][ darn ]");
  }

/****************************************************************/

   /* This function is given the co-ordinates of 3 points */
   /* and it tries to calculate the centre and radius of  */
   /* a circle that passes through the 3 points.          */

pts_to_arc(px1,py1,px2,py2,px3,py3,xx,yy,rr)
int px1,py1,px2,py2,px3,py3, *xx, *yy, *rr;
  {
  register long rad, rad2;
  double a1, b1, a2, b2, a3, b3, num, den, cx, cy;

  a1 = (double) px1; b1 = (double) py1;
  a2 = (double) px2; b2 = (double) py2;
  a3 = (double) px3; b3 = (double) py3;

  num = (b1-b2)*(b1-b3)*(b3-b2) - a1*(a2-a1)*(b3-b2) + a3*(a2-a3)*(b1-b2);
  den = (a2-a3)*(b1-b2) - (a2-a1)*(b3-b2);
  if (den) cx = (num/den + a2)/2;        /* a solution for x center */
  else cx = 0;                           /* a straight line */

  num = (a1-a2)*(a1-a3)*(a3-a2) - b1*(b2-b1)*(a3-a2) + b3*(b2-b3)*(a1-a2);
  den = (b2-b3)*(a1-a2) - (b2-b1)*(a3-a2);
  if (den) cy = (num/den + b2)/2;        /* a solution for y center */
  else cy = 0;                           /* a straight line */

  rad2 = (long)((a3-cx)*(a3-cx) + (b3-cy)*(b3-cy));  /* radius ^ 2 */
  if (rad2>250000L) rad2=250000;
  for (rad=0L; rad*rad<rad2; rad++);         /* find square root */

  *xx = (int) cx;
  *yy = (int) cy;
  *rr = (int) rad;
  }

/****************************************************************/

    /* return angle of inclination of line (cx,cy)-(x1,y1) */

int calc_angle (cx,cy,x1,y1)
int cx,cy,x1,y1;
  {
  register int dx, dy, a,b;
  double slope, angle;

  dx = x1-cx;
  dy = -(y1-cy);    /* backwards because vertical is upside down */

  if (dx==0 && dy>0)  return(900);
  if (dx==0 && dy<0)  return(2700);
  if (dx>=0  && dy==0) return(0);
  if (dx<0  && dy==0) return(1800);

  a = abs(dx); b = abs(dy);

  slope = (double)(b)/(double)(a);
  angle = atan(slope)*1800.0/3.14159265;       /* 0 to 900 decidegrees */

  if (dx<0) angle = 1800.0-angle;
  if (dy<0) angle = 3600.0-angle;

  return( (int)angle );
  }

/****************************************************************/

wait_mouse (x, y, but)
register int *x, *y, *but;
  {
  int oldx, oldy, oldbut;

  vq_mouse(handle,&oldbut,&oldx,&oldy);
  if (snap_flag)
       snap(&oldx,&oldy);
  do
    {
    vq_mouse(handle,but,x,y);
    if (snap_flag)
         snap (x,y);
    } while (*x==oldx && *y==oldy & *but==oldbut);
  }

/****************************************************************/

rubber_shape (shape_type,xstart,ystart, xend, yend)
int xstart,ystart, shape_type, *xend, *yend;
  {
  int curx=xstart, cury=ystart, radx, rady, not_pressed=TRUE;

  vswr_mode(handle,3);
  vsl_udsty(handle,0xA8A8);
  vsl_type(handle,7);    /* dotted lines */
  vsl_width(handle,1);

  arr_pnts[0]= arr_pnts[2] = arr_pnts[4] = arr_pnts[6] =arr_pnts[8] = xstart;
  arr_pnts[1] = arr_pnts[3] =arr_pnts[5] = arr_pnts[7] = arr_pnts[9]= ystart;

  wait_mouse(&curx,&cury,&but,&state);

  while (but | not_pressed) {
    if (but) not_pressed = FALSE;
    graf_mouse(M_OFF,0L);
    if (shape_type==LINE) {
      arr_pnts[2] = curx; arr_pnts[3] = cury;
      v_pline(handle,2,arr_pnts);
     }
    else {
      arr_pnts[2] = curx;
      arr_pnts[4] = curx; arr_pnts[5] = cury;
      arr_pnts[7] = cury;
      v_pline(handle,5,arr_pnts);
      if (shape_type==ELLIPSE) {
        radx = (curx-xstart)/2;
        rady = (cury-ystart)/2;
        v_ellarc(handle,xstart+radx,ystart+rady,radx,rady,0,3595);
       }
     }
    graf_mouse(M_ON,0L);
    wait_mouse(&curx,&cury,&but,&state);
    graf_mouse(M_OFF,0L);

    if (shape_type==LINE) v_pline(handle,2,arr_pnts);
    else {
      v_pline(handle,5,arr_pnts);   /* undraw shape as moving or exiting */
      if (shape_type==ELLIPSE)
        v_ellarc(handle,xstart+radx,ystart+rady,radx,rady,0,3595);
      }
    graf_mouse(M_ON,0L);
   };

  vswr_mode(handle,copy_mode);  /* restore drawing mode */
  vsl_type(handle,1);

  *xend = curx;
  *yend = cury;
  }

/****************************************************************/

clear_work()
  {           /* erase work area */
  register long word, limit;
  register int *zap;

  zap = bigbuf;
  limit = (long)(xsize)*(long)(ysize)/16L*(long)rplane;
  for (word=0; word<limit; word++) *zap++ = 0;

  Setpalette(palette[rez]);

  buf_to_scr(0,0,wwork,hwork);

  blockh = blockw = block_mode = 0;
  menu[MARK].ob_state &= ~CHECKED;
  menu[COPY].ob_state &= ~CHECKED;
  wind_set(wi_handle, WF_NAME," no name ",0,0);

  xpos = (xsize-wwork)/2;
  ypos = (ysize-hwork)/2;

  update_slider(1,1); update_slider(-1,-1);   /* reset sliders */
  scr_to_undo();

  valid_fn = FALSE;
  drew = TRUE;

  mdFill=7;
  mdLW=0;      /* line width 1 */
  mdSS=2;      /* snap size 8 */
  mdLS=0;
  mdLE=0;
  LineWidth = 1;
  SnapSize = 8;
  }

/****************************************************************/

set_color (new)
int new;
  {
  vsf_color(handle,new);
  vsl_color(handle,new);
  vsm_color(handle,new);
  }

/****************************************************************/

do_zoom ()
  {                       /* prepares zoom window */
  register int pix, zx, zy, z;
  int ar[4], old_attrib[4];

  graf_mouse(M_OFF,0L);

  zxwork = xwork+zoom_wwork; zywork = ywork;
  zwwork = true_wwork-zoom_wwork-1;
  zhwork = hwork;

  zbox_x = xwork + zoom_wwork/2 - 8;
  zbox_y = ywork + zoom_hwork/2 - 8;

  set_clip(zxwork,zywork,zwwork,zhwork);

  vswr_mode(handle,1);              /* replace mode for zoom box */

  vqf_attributes(handle,old_attrib);
  vsf_color(handle,0);                 /* white fill */
  vsf_interior(handle,0);
  vsf_style(handle,0);
  ar[0] = zxwork;
  ar[1] = zywork;
  ar[2] = zxwork + zwwork;
  ar[3] = zywork + zhwork;
  v_bar(handle,ar);

  mag_x = (zwwork-6)/zbox_w;
  mag_y = (zhwork-6)/zbox_h;

  vsf_color(handle,1);                 /* black fill */
  vsf_interior(handle,2);
  vsf_style(handle,8);

  for (pix=0; pix<zbox_w; pix++) {
    ar[0] = ar[2] = zxwork + pix*mag_x +2;
    ar[1] = zywork+2;
    ar[3] = zywork + zbox_h*mag_y;
    v_bar(handle,ar);
   }

  for (pix=0; pix<zbox_h; pix++) {
    ar[1] = ar[3] = zywork + pix*mag_y +2;
    ar[0] = zxwork+2;
    ar[2] = zxwork + zbox_w*mag_x;
    v_bar(handle,ar);
   }

  update_zoom(0,0,zbox_w,zbox_h);

  vsf_color(handle,old_attrib[1]);
  vsf_interior(handle,old_attrib[0]);
  vsf_style(handle,old_attrib[2]);

  set_clip(xwork,ywork,wwork,hwork);

  graf_mouse(M_ON,0L);
  }

/****************************************************************/

update_zoom (zx1,zy1,zx2,zy2)
int zx1, zx2, zy1, zy2;
  {                   /* draws the large pixels in zoom window */
  register int zx, zy;
  int z, ar[4], old_attrib[4];

  graf_mouse(M_OFF,0L);

  set_clip(zxwork,zywork,zwwork,zhwork);

  vswr_mode(handle,1);              /* replace mode for zoom box */

  vqf_attributes(handle,old_attrib);
  vsf_interior(handle,1);

  for (zy=zy1; zy<zy2; zy++)
    for (zx=zx1; zx<zx2; zx++) {
      v_get_pixel (handle,zbox_x+zx,zbox_y+zy,&z,&z);
      vsf_color(handle,z);
      ar[0] = zxwork + zx*mag_x + 1 +2;
      ar[1] = zywork + zy*mag_y + 1 +2;
      ar[2] = zxwork + zx*mag_x + mag_x - 1 +2;
      ar[3] = zywork + zy*mag_y + mag_y - 1 +2;
      v_bar(handle,ar);
    }

  vsf_color(handle,old_attrib[1]);
  vsf_interior(handle,old_attrib[0]);
  vsf_style(handle,old_attrib[2]);

  set_clip(xwork,ywork,wwork,hwork);

  graf_mouse(M_ON,0L);

  drew=FALSE;
  }


/****************************************************************/

int mpStyleObj[36] =
       {
       FILL0, FILL1, FILL2, FILL3, FILL4, FILL5, FILL6, FILL7, FILL8,
       FILL9, FILL10, FILL11, FILL12, FILL13, FILL14, FILL15, FILL16, FILL17,
       FILL18, FILL19, FILL20, FILL21, FILL22, FILL23, FILL24, FILL25, FILL26,
       FILL27, FILL28, FILL29, FILL30, FILL31, FILL32, FILL33, FILL34, FILL35
       };

select_fill()
    {
    register int but;
    int cx, cy, cw, ch, xc, yc;
    register int FillT, xFill, yFill, wFill, hFill;
    int xTop, yTop;
    int ar[8];
    register OBJECT *obj;
    register int oldFill=mdFill;

    form_center(fill_box, &cx, &cy, &cw, &ch);
    set_clip(cx, cy, cw, ch);
    scr_to_buf(cx-xwork,cy-ywork,cw+4,ch+4);      /* buffer the box */
    xc = cx + cw/2;
    yc = cy + ch/2;
    form_dial(FMD_START, cx, cy, cw, ch, cx, cy, cw, ch);
    form_dial(FMD_GROW, xc,yc,0,0, cx, cy, cw, ch);

    for (FillT=0; FillT<36;)
       fill_box[mpStyleObj[FillT++]].ob_state &= ~SELECTED;

    graf_mouse(M_OFF,0L);
    objc_draw(fill_box, 0, 10, cx, cy, cw, ch);

    xTop = cx + fill_box[FILL_BOX].ob_x;
    yTop = cy + fill_box[FILL_BOX].ob_y;
    for (FillT=0; FillT<36; FillT++)
       {
       obj = &fill_box[mpStyleObj[FillT]];
       xFill = xTop + obj->ob_x;
       yFill = yTop + obj->ob_y;
       obj->ob_flags = SELECTABLE | EXIT;
       vsf_interior(handle,(FillT>23)?3:2);
       vsf_style(handle,FillT%24);
       vsf_color(handle,draw_color);
       v_contourfill(handle,xFill+8,yFill+8,-1);
       }

    obj = &fill_box[FILLSHOW];
    xFill = xTop + obj->ob_x + 3;
    yFill = yTop + obj->ob_y + 2;
    wFill = obj->ob_width-1;
    hFill = obj->ob_height+1;
    ar[0] = xFill;
    ar[1] = yFill;
    ar[2] = xFill;
    ar[3] = yFill+hFill;
    ar[4] = xFill+wFill;
    ar[5] = yFill+hFill;
    ar[6] = xFill+wFill;
    ar[7] = yFill;
    vsf_interior(handle,(mdFill>23)?3:2);
    vsf_style(handle,mdFill%24);
    vsf_color(handle,draw_color);
    v_fillarea(handle,4,ar);
    graf_mouse(M_ON,0L);

    do
        {
        but = form_do(fill_box, 0);
        fill_box[but].ob_state &= ~SELECTED;

        FillT=0;
        if (but==FILL_OK)
            while (mpStyleObj[FillT] != but)
                FillT++;
        else if (but!=FILL_NO)
            {
            objc_draw(fill_box, but, 1, 0,0, 639,399);
            while (mpStyleObj[FillT] != but)
                FillT++;
            mdFill=FillT;
            vsf_interior(handle,(mdFill>23)?3:2);
            vsf_style(handle,mdFill%24);
            graf_mouse(M_OFF,0L);
            v_fillarea(handle,4,ar);
            graf_mouse(M_ON,0L);
            }
         else
            mdFill=oldFill;
        }
     while ((but!=FILL_OK) && (but!=FILL_NO));

    form_dial(FMD_SHRINK, xc,yc,0,0, cx, cy, cw, ch);
    form_dial(FMD_FINISH, 0,0,0,0, cx, cy, cw, ch);
    buf_to_scr(cx-xwork,cy-ywork,cw+4,ch+4);      /* unbuffer the box */
    }

/****************************************************************/

int mpLWObj[5] =
       {
       LW1, LW3, LW5, LW7, LW9
       };

int mpSSObj[5] =
       {
       SS4, SS6, SS8, SS12, SS16
       };

int mpLSObj[3] =
       {
       LS_SQR, LS_ARROW, LS_RND
       };

int mpLEObj[3] =
       {
       LE_SQR, LE_ARROW, LE_RND
       };

select_other()
    {
    int but;
    int cx, cy, cw, ch, xc, yc;
    int mdT;

    form_center(default_box, &cx, &cy, &cw, &ch);
    set_clip(cx, cy, cw, ch);
    scr_to_buf(cx-xwork,cy-ywork,cw+4,ch+4);      /* buffer the box */
    xc = cx + cw/2;
    yc = cy + ch/2;
    form_dial(FMD_START, cx, cy, cw, ch, cx, cy, cw, ch);
    form_dial(FMD_GROW, xc,yc,0,0, cx, cy, cw, ch);

    for (mdT=0; mdT<5;)
        {
        default_box[mpLWObj[mdT]].ob_state &= ~SELECTED;
        default_box[mpSSObj[mdT++]].ob_state &= ~SELECTED;
        }
    for (mdT=0; mdT<3;)
        {
        default_box[mpLSObj[mdT]].ob_state &= ~SELECTED;
        default_box[mpLEObj[mdT++]].ob_state &= ~SELECTED;
        }
    default_box[mpLWObj[mdLW]].ob_state |= SELECTED;
    default_box[mpSSObj[mdSS]].ob_state |= SELECTED;
    default_box[mpLSObj[mdLS]].ob_state |= SELECTED;
    default_box[mpLEObj[mdLE]].ob_state |= SELECTED;

    graf_mouse(M_OFF,0L);
    objc_draw(default_box, 0, 10, cx, cy, cw, ch);
    graf_mouse(M_ON,0L);

    but = form_do(default_box, 0);
    default_box[but].ob_state &= ~SELECTED;
    if (but==OTHER_OK)
        {
        for (mdT=0; mdT<5; mdT++)
              {
              if (default_box[mpLWObj[mdT]].ob_state & SELECTED)
                  mdLW = mdT;
              if (default_box[mpSSObj[mdT]].ob_state & SELECTED)
                  mdSS = mdT;
              }
        for (mdT=0; mdT<3; mdT++)
              {
              if (default_box[mpLSObj[mdT]].ob_state & SELECTED)
                  mdLS = mdT;
              if (default_box[mpLEObj[mdT]].ob_state & SELECTED)
                  mdLE = mdT;
              }
        }
    form_dial(FMD_SHRINK, xc,yc,0,0, cx, cy, cw, ch);
    form_dial(FMD_FINISH, 0,0,0,0, cx, cy, cw, ch);
    buf_to_scr(cx-xwork,cy-ywork,cw+4,ch+4);      /* unbuffer the box */

    LineWidth = mpLW[mdLW];
    SnapSize = mpSS[mdSS];
    }

/****************************************************************/

snap (px, py)
register int *px, *py;
        {
        register int x = *px+SnapSize/3, y = *py+SnapSize/3;
        *px -= x%SnapSize;
        *py -= y%SnapSize;
        }

/****************************************************************/
