/* w_editor.c
 *
 * Micropolis, Unix Version.  This game was released for the Unix platform
 * in or about 1990 and has been modified for inclusion in the One Laptop
 * Per Child program.  Copyright (C) 1989 - 2007 Electronic Arts Inc.  If
 * you need assistance with this program, you may contact:
 *   http://wiki.laptop.org/go/Micropolis  or email  micropolis@laptop.org.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.  You should have received a
 * copy of the GNU General Public License along with this program.  If
 * not, see <http://www.gnu.org/licenses/>.
 * 
 *             ADDITIONAL TERMS per GNU GPL Section 7
 * 
 * No trademark or publicity rights are granted.  This license does NOT
 * give you any right, title or interest in the trademark SimCity or any
 * other Electronic Arts trademark.  You may not distribute any
 * modification of this program using the trademark SimCity or claim any
 * affliation or association with Electronic Arts Inc. or its employees.
 * 
 * Any propagation or conveyance of this program must include this
 * copyright notice and these terms.
 * 
 * If you convey this program (or any modifications of it) and assume
 * contractual liability for the program to recipients of it, you agree
 * to indemnify Electronic Arts for any liability that those contractual
 * assumptions impose on Electronic Arts.
 * 
 * You may not misrepresent the origins of this program; modified
 * versions of the program must be marked as such and not identified as
 * the original program.
 * 
 * This disclaimer supplements the one included in the General Public
 * License.  TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
 * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
 * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK.  THE ENTIRE RISK OF
 * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU.  ELECTRONIC ARTS
 * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
 * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
 * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
 * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
 * USAGE, OR TRADE PRACTICE.  ELECTRONIC ARTS DOES NOT WARRANT AGAINST
 * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
 * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
 * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
 * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
 * CORRECTED.  NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
 * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY.  SOME
 * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
 * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
 * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
 * NOT APPLY TO YOU.
 */
#include "sim.h"


Tcl_HashTable EditorCmds;
int DoOverlay = 2;
int BobHeight = 8;


extern Tk_ConfigSpec TileViewConfigSpecs[];

void ClipTheOverlay(SimView *view);
void DrawTheOverlay(SimView *view, GC gc, Pixmap pm, int color, 
	       int top, int bottom, int left, int right,
	       int onoverlay);
void DrawOverlay(SimView *view);
void DrawCursor(SimView *view);
void DrawPending(SimView *view);
void DrawOutside(SimView *view);
void HandleAutoGoto(SimView *view);


int EditorCmdconfigure(VIEW_ARGS)
{
  int result = TCL_OK;

  if (argc == 2) {
    result = Tk_ConfigureInfo(interp, view->tkwin, TileViewConfigSpecs,
			      (char *) view, (char *) NULL, 0);
  } else if (argc == 3) {
    result = Tk_ConfigureInfo(interp, view->tkwin, TileViewConfigSpecs,
			      (char *) view, argv[2], 0);
  } else {
    result = ConfigureTileView(interp, view, argc-2, argv+2,
			       TK_CONFIG_ARGV_ONLY);
  }
  return TCL_OK;
}


int EditorCmdposition(VIEW_ARGS)
{
  if ((argc != 2) && (argc != 4)) {
    return TCL_ERROR;
  }
  if (argc == 4) {
    if ((Tcl_GetInt(interp, argv[2], &view->w_x) != TCL_OK) ||
	(Tcl_GetInt(interp, argv[3], &view->w_y) != TCL_OK)) {
      return TCL_ERROR;
    }
  }
  sprintf(interp->result, "%d %d", view->w_x, view->w_y);
  return TCL_OK;
}


int EditorCmdsize(VIEW_ARGS)
{
  if ((argc != 2) && (argc != 4)) {
    return TCL_ERROR;
  }
  if (argc == 4) {
    int w, h;
    
    if (Tcl_GetInt(interp, argv[2], &w) != TCL_OK) {
      return TCL_ERROR;
    }
    if (Tcl_GetInt(interp, argv[3], &h) != TCL_OK) {
      return TCL_ERROR;
    }
    view->w_width = w;
    view->w_height = h;
  }
  sprintf(interp->result, "%d %d", view->w_width, view->w_height);
  return TCL_OK;
}


int EditorCmdAutoGoto(VIEW_ARGS)
{
  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }
  if (argc == 3) {
    int val;

    if (Tcl_GetInt(interp, argv[2], &val) != TCL_OK) {
      return TCL_ERROR;
    }
    view->auto_goto = val;
    view->auto_going = view->auto_x_goal = view->auto_y_goal = 0;
  }
  sprintf(interp->result, "%d", view->auto_goto);
  return TCL_OK;
}


int EditorCmdSound(VIEW_ARGS)
{
  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }
  if (argc == 3) {
    int val;

    if (Tcl_GetInt(interp, argv[2], &val) != TCL_OK) {
      return TCL_ERROR;
    }
    view->sound = val;
    view->auto_going = view->auto_x_goal = view->auto_y_goal = 0;
  }
  sprintf(interp->result, "%d", view->sound);
  return TCL_OK;
}


int EditorCmdSkip(VIEW_ARGS)
{
  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }
  if (argc == 3) {
    int val;

    if (Tcl_GetInt(interp, argv[2], &val) != TCL_OK) {
      return TCL_ERROR;
    }
    view->skip = view->skips = val; // XXX? why setting skips too?
  }
  sprintf(interp->result, "%d", view->skips);
  return TCL_OK;
}


int EditorCmdUpdate(VIEW_ARGS)
{
  if (argc != 2) {
    return TCL_ERROR;
  }
  view->skip = 0;
  return TCL_OK;
}


int EditorCmdPan(VIEW_ARGS)
{
  if ((argc != 2) && (argc != 4)) {
    return TCL_ERROR;
  }
  if (argc == 4) {
    int x, y;

    if (Tcl_GetInt(interp, argv[2], &x) != TCL_OK) {
      return TCL_ERROR;
    }
    if (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) {
      return TCL_ERROR;
    }
    DoPanTo(view, x, y); Kick();
  }
  sprintf(interp->result, "%d %d", view->pan_x, view->pan_y);
  return TCL_OK;
}


int EditorCmdToolConstrain(VIEW_ARGS)
{
  int x = -1, y = -1, tx, ty;

  if (argc != 4) {
    return TCL_ERROR;
  }

  if (Tcl_GetInt(interp, argv[2], &x) != TCL_OK) {
    return TCL_ERROR;
  }
  if (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) {
    return TCL_ERROR;
  }
  view->tool_x_const = -1; view->tool_y_const = -1;
  ViewToTileCoords(view, x, y, &tx, &ty);
  view->tool_x_const = (x == -1) ? -1 : tx;
  view->tool_y_const = (y == -1) ? -1 : ty;
  return TCL_OK;
}


int EditorCmdToolState(VIEW_ARGS)
{
  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }
  if (argc == 3) {
    int state;

    if (Tcl_GetInt(interp, argv[2], &state) != TCL_OK) {
      return TCL_ERROR;
    }
    setWandState(view, state);
  }
  sprintf(interp->result, "%d", view->tool_state);
  return TCL_OK;
}


int EditorCmdToolMode(VIEW_ARGS)
{
  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }
  if (argc == 3) {
    int mode;

    if (Tcl_GetInt(interp, argv[2], &mode) != TCL_OK) {
      return TCL_ERROR;
    }
    view->tool_mode = mode;
  }
  sprintf(interp->result, "%d", view->tool_mode);
  return TCL_OK;
}


int EditorCmdDoTool(VIEW_ARGS)
{
  int tool, x, y;

  if (argc != 5) {
    return TCL_ERROR;
  }

  if ((Tcl_GetInt(interp, argv[2], &tool) != TCL_OK) ||
      (tool < 0) ||
      (tool > lastState) ||
      (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) ||
      (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)) {
    return TCL_ERROR;
  }

  DoTool(view, tool, x, y); Kick();
  return TCL_OK;
}


int EditorCmdToolDown(VIEW_ARGS)
{
  int x, y;

  if (argc != 4) {
    return TCL_ERROR;
  }

  if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
      (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
    return TCL_ERROR;
  }

  ToolDown(view, x, y); Kick();
  return TCL_OK;
}


int EditorCmdToolDrag(VIEW_ARGS)
{
  int x, y;

  if (argc != 4) {
    return TCL_ERROR;
  }

  if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
      (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
    return TCL_ERROR;
  }

  ToolDrag(view, x, y); Kick();
  return TCL_OK;
}


int EditorCmdToolUp(VIEW_ARGS)
{
  int x, y;

  if (argc != 4) {
    return TCL_ERROR;
  }

  if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
      (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
    return TCL_ERROR;
  }

  ToolUp(view, x, y); Kick();
  return TCL_OK;
}


int EditorCmdPanStart(VIEW_ARGS)
{
  int x, y;

  if (argc != 4) {
    return TCL_ERROR;
  }

  if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
      (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
    return TCL_ERROR;
  }

  view->last_x = x;
  view->last_y = y;
  return TCL_OK;
}


int EditorCmdPanTo(VIEW_ARGS)
{
  int x, y, dx, dy;

  if (argc != 4) {
    return TCL_ERROR;
  }

  if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
      (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
    return TCL_ERROR;
  }

  dx = (view->tool_x_const == -1) ? (view->last_x - x) : 0;
  dy = (view->tool_y_const == -1) ? (view->last_y - y) : 0;
  if (dx || dy) {
    view->last_x = x;
    view->last_y = y;
    DoPanBy(view, dx, dy); Kick();
  }
  return TCL_OK;
}


int EditorCmdPanBy(VIEW_ARGS)
{
  int dx, dy;

  if (argc != 4) {
    return TCL_ERROR;
  }

  if ((Tcl_GetInt(interp, argv[2], &dx) != TCL_OK) ||
      (Tcl_GetInt(interp, argv[3], &dy) != TCL_OK)) {
    return TCL_ERROR;
  }

  DoPanBy(view, dx, dy); Kick();
  return TCL_OK;
}


int EditorCmdTweakCursor(VIEW_ARGS)
{
  XWarpPointer (view->x->dpy, None, None, 0, 0, 0, 0, 0, 0);

  return TCL_OK;
}


int EditorCmdVisible(VIEW_ARGS)
{
  int visible;

  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }

  if (argc == 3) {
    if ((Tcl_GetInt(interp, argv[2], &visible) != TCL_OK) ||
	(visible < 0) || (visible > 1)) {
      return TCL_ERROR;
    }

    visible = visible && Tk_IsMapped(view->tkwin);
    view->visible = visible;
  }

  sprintf(interp->result, "%d", view->visible);
  return TCL_OK;
}


int EditorCmdKeyDown(VIEW_ARGS)
{

  if (argc != 3) {
    return TCL_ERROR;
  }

  doKeyDown(view, argv[2][0]);
  return TCL_OK;
}


int EditorCmdKeyUp(VIEW_ARGS)
{

  if (argc != 3) {
    return TCL_ERROR;
  }

  doKeyUp(view, argv[2][0]);
  return TCL_OK;
}


int EditorCmdTileCoord(VIEW_ARGS)
{
  int x, y;

  if ((argc != 2) && (argc != 4)) {
    return TCL_ERROR;
  }

  if (Tcl_GetInt(interp, argv[2], &x) != TCL_OK) {
    return TCL_ERROR;
  }
  if (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) {
    return TCL_ERROR;
  }

  ViewToTileCoords(view, x, y, &x, &y);

  sprintf(interp->result, "%d %d", x, y);
  return TCL_OK;
}


int EditorCmdChalkStart(VIEW_ARGS)
{
  int x, y;

  if (argc != 4) {
    return TCL_ERROR;
  }

  if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
      (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
    return TCL_ERROR;
  }

  ChalkStart(view, x, y, COLOR_WHITE);
  return TCL_OK;
}


int EditorCmdChalkTo(VIEW_ARGS)
{
  int x, y;

  if (argc != 4) {
    return TCL_ERROR;
  }

  if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
      (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
    return TCL_ERROR;
  }

  ChalkTo(view, x, y);
  return TCL_OK;
}


int EditorCmdAutoGoing(VIEW_ARGS)
{
  int flag;

  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }

  if (argc == 3) {
    if ((Tcl_GetInt(interp, argv[2], &flag) != TCL_OK)) {
      return TCL_ERROR;
    }

    view->auto_going = flag;
    if (view->auto_goto == -1)
      view->auto_goto = 0;
  }

  sprintf(interp->result, "%d", view->auto_going);
  return TCL_OK;
}


int EditorCmdAutoSpeed(VIEW_ARGS)
{
  int speed;

  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }

  if (argc == 3) {
    if ((Tcl_GetInt(interp, argv[2], &speed) != TCL_OK) ||
	(speed < 1)) {
      return TCL_ERROR;
    }

    view->auto_speed = speed;
  }

  sprintf(interp->result, "%d", view->auto_speed);
  return TCL_OK;
}


int EditorCmdAutoGoal(VIEW_ARGS)
{
  if ((argc != 2) && (argc != 4)) {
    return TCL_ERROR;
  }
  if (argc == 4) {
    int x, y, dx, dy;

    if (Tcl_GetInt(interp, argv[2], &x) != TCL_OK) {
      return TCL_ERROR;
    }
    if (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) {
      return TCL_ERROR;
    }
    view->auto_x_goal = x;
    view->auto_y_goal = y;
    /* actually go there if more than a block away */
    dx = view->pan_x - x;
    dy = view->pan_y - y;
    view->auto_going = (((dx * dx) + (dy * dy)) > (64 * 64));
    if ((view->auto_going != 0) &&
	(view->auto_goto == 0))
      view->auto_goto = -1;
  }

  sprintf(interp->result, "%d %d", view->auto_x_goal, view->auto_y_goal);
  return TCL_OK;
}


int EditorCmdSU(VIEW_ARGS)
{
  int su;

  if ((argc != 2) && (argc != 4)) {
    return TCL_ERROR;
  }

  if (argc == 4) {
    if ((strcmp(argv[3], "xyzzy") != 0) ||
	(Tcl_GetInt(interp, argv[2], &su) != TCL_OK)) {
      return TCL_ERROR;
    }

    view->super_user = su;
  }

  sprintf(interp->result, "%d", view->super_user);
  return TCL_OK;
}


int EditorCmdShowMe(VIEW_ARGS)
{
  int flag;

  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }

  if (argc == 3) {
    if (Tcl_GetInt(interp, argv[2], &flag) != TCL_OK) {
      return TCL_ERROR;
    }

    view->show_me = flag;
  }

  sprintf(interp->result, "%d", view->show_me);
  return TCL_OK;
}


int EditorCmdFollow(VIEW_ARGS)
{
  SimSprite *sprite;

  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }

  if (argc == 3) {
    view->follow = NULL;
    if (argv[2][0] != '\0') {
      for (sprite = sim->sprite; sprite != NULL; sprite = sprite->next) {
	if (strcmp(sprite->name, argv[2]) == 0) {
	  view->follow = sprite;
	  break;
	}
      }
    }

    if (view->follow != NULL) {
      HandleAutoGoto(view);
    }
  }

  sprintf(interp->result, "%s",
	  (view->follow == NULL) ? "" : view->follow->name);
  return TCL_OK;
}


int EditorCmdShowOverlay(VIEW_ARGS)
{
  int flag;

  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }

  if (argc == 3) {
    if ((Tcl_GetInt(interp, argv[2], &flag) != TCL_OK)) {
      return TCL_ERROR;
    }

    view->show_overlay = flag;
  }

  sprintf(interp->result, "%d", view->show_overlay);
  return TCL_OK;
}


int EditorCmdOverlayMode(VIEW_ARGS)
{
  int flag;

  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }

  if (argc == 3) {
    if ((Tcl_GetInt(interp, argv[2], &flag) != TCL_OK)) {
      return TCL_ERROR;
    }

    view->overlay_mode = flag;
  }

  sprintf(interp->result, "%d", view->overlay_mode);
  return TCL_OK;
}


int EditorCmdDynamicFilter(VIEW_ARGS)
{
  int val;

  if ((argc != 2) && (argc != 3)) {
    return TCL_ERROR;
  }

  if (argc == 3) {
    if ((Tcl_GetInt(interp, argv[2], &val) != TCL_OK)) {
      return TCL_ERROR;
    }

    view->dynamic_filter = val;
  }

  sprintf(interp->result, "%d", view->dynamic_filter);
  return TCL_OK;
}


int EditorCmdWriteJpeg(VIEW_ARGS)
{
#if 0
  int val;
  char *fileName = argv[2];
#endif

  if (argc != 3) {
    return TCL_ERROR;
  }
  
  // Write a jpeg file of this view.

  return TCL_OK;
}


void
editor_command_init(void)
{
  extern int TileViewCmd(CLIENT_ARGS);

  Tcl_CreateCommand(tk_mainInterp, "editorview", TileViewCmd,
		    (ClientData)MainWindow, (void (*)()) NULL);

  Tcl_InitHashTable(&EditorCmds, TCL_STRING_KEYS);

#define EDITOR_CMD(name) HASHED_CMD(Editor, name)

  EDITOR_CMD(configure);
  EDITOR_CMD(position);
  EDITOR_CMD(size);
  EDITOR_CMD(AutoGoto);
  EDITOR_CMD(Sound);
  EDITOR_CMD(Skip);
  EDITOR_CMD(Update);
  EDITOR_CMD(Pan);
  EDITOR_CMD(ToolConstrain);
  EDITOR_CMD(ToolState);
  EDITOR_CMD(ToolMode);
  EDITOR_CMD(DoTool);
  EDITOR_CMD(ToolDown);
  EDITOR_CMD(ToolDrag);
  EDITOR_CMD(ToolUp);
  EDITOR_CMD(PanStart);
  EDITOR_CMD(PanTo);
  EDITOR_CMD(PanBy);
  EDITOR_CMD(TweakCursor);
  EDITOR_CMD(Visible);
  EDITOR_CMD(KeyDown);
  EDITOR_CMD(KeyUp);
  EDITOR_CMD(TileCoord);
  EDITOR_CMD(ChalkStart);
  EDITOR_CMD(ChalkTo);
  EDITOR_CMD(AutoGoing);
  EDITOR_CMD(AutoSpeed);
  EDITOR_CMD(AutoGoal);
  EDITOR_CMD(SU);
  EDITOR_CMD(ShowMe);
  EDITOR_CMD(Follow);
  EDITOR_CMD(ShowOverlay);
  EDITOR_CMD(OverlayMode);
  EDITOR_CMD(DynamicFilter);
}


int
DoEditorCmd(CLIENT_ARGS)
{
  SimView *view = (SimView *) clientData;
  Tcl_HashEntry *ent;
  int result = TCL_OK;
  int (*cmd)();

  if (argc < 2) {
    return TCL_ERROR;
  }

  if ((ent = Tcl_FindHashEntry(&EditorCmds, argv[1]))) {
    cmd = (int (*)())ent->clientData;
    Tk_Preserve((ClientData) view);
    result = cmd(view, interp, argc, argv);
    Tk_Release((ClientData) view);
  } else {
    Tcl_AppendResult(interp, "unknown command name: \"",
		     argv[0], " ", argv[1], "\".", (char *) NULL);
    result = TCL_ERROR;
  }
  return result;
}



/*************************************************************************/


void
DoNewEditor(SimView *view)
{
  sim->editors++; view->next = sim->editor; sim->editor = view;
  view->invalid = 1;
}


void
DoUpdateEditor(SimView *view)
{
  int dx, dy, i;

  view->updates++;

  if (!view->visible) {
    return;
  }

  if ((!ShakeNow) &&
//      (!view->invalid) &&
      (!view->update) &&
      (sim_skips ||
       view->skips)) {
    if (sim_skips) {
      if (sim_skip > 0) {
	return;
      }
    } else {
      if (view->skip > 0) {
	--view->skip;
	return;
      } else {
	view->skip = view->skips;
      }
    }
  }

  view->skips = 0;
  view->update = 0;

  HandleAutoGoto(view);

  if (DoAnimation && SimSpeed && !heat_steps && !TilesAnimated) {
    TilesAnimated = 1;
    animateTiles();
  }

  if (view->invalid) {

    switch (view->type) {

    case X_Mem_View:
      MemDrawBeegMapRect(view, view->tile_x, view->tile_y,
			 view->tile_width, view->tile_height);
      break;

    case X_Wire_View:
      WireDrawBeegMapRect(view, view->tile_x, view->tile_y,
			  view->tile_width, view->tile_height);
      break;

    }

    XCopyArea(view->x->dpy, view->pixmap, view->pixmap2, view->x->gc,
	      0, 0, view->screen_width, view->screen_height,
	      view->screen_x, view->screen_y);
    DrawOutside(view);
    if (PendingTool != -1) {
      DrawPending(view);
    }
    DrawObjects(view);
    if (view->show_overlay) {
      DrawOverlay(view);
    }
  }

  for (dx = dy = i = 0; i < ShakeNow; i++) {
    dx += Rand(16) - 8;
    dy += Rand(16) - 8;
  }

  XCopyArea(view->x->dpy, view->pixmap2,
	    Tk_WindowId(view->tkwin), view->x->gc,
	    0, 0, view->w_width, view->w_height, dx, dy);

  DrawCursor(view);

  view->invalid = 0;
}


void
HandleAutoGoto(SimView *view)
{
  if (view->follow != NULL) {
    int x = view->follow->x + view->follow->x_hot,
        y = view->follow->y + view->follow->y_hot;

    if ((x != view->pan_x) ||
	(y != view->pan_y)) {
      DoPanTo(view, x, y);
    }
  } else if (view->auto_goto &&
	     view->auto_going &&
	     (view->tool_mode == 0)) {
    int dx, dy;
    int speed;
    double dist, sloth;

    speed = view->auto_speed;

    if (view->auto_going < 5) {
      sloth = ((double)view->auto_going) / 5.0;
    } else {
      sloth = 1.0;
    }

    dx = view->auto_x_goal - view->pan_x;
    dy = view->auto_y_goal - view->pan_y;

    dist = sqrt((double)((dx * dx) + (dy * dy)));

    if (dist < (speed * sloth)) {
      view->auto_going = 0;
      if (view->auto_goto == -1)
	view->auto_goto = 0;
      DoPanTo(view, view->auto_x_goal, view->auto_y_goal);
      NewMap = 1;
      DidStopPan(view);
    } else {
      double atan2(), cos(), sin();
      double direction, vx, vy;
      double co, si;

      direction = (double)atan2((double)dy, (double)dx);
      co = (double)cos(direction);
      si = (double)sin(direction);
      vx = co * (double)speed;
      vy = si * (double)speed;

      vx *= sloth; vy *= sloth;
      speed *= sloth;

      vx += 0.5; vy += 0.5;

      DoPanBy(view, (int)(vx), (int)(vy));
      view->auto_going++;
    }
  }
}

void
DrawOutside(SimView *view)
{
  Pixmap pm = view->pixmap2;
  int left = (view->w_width / 2) - view->pan_x;
  int right = left + view->i_width;
  int top = (view->w_height / 2) - view->pan_y;
  int bottom = top + view->i_height;

  if ((top > 0) || (bottom < view->w_height) ||
      (left > 0) || (right < view->w_width)) {
    if (view->x->color) {
      XSetForeground(view->x->dpy, view->x->gc,
		     view->pixels[COLOR_BLACK]);
    } else {
      XSetForeground(view->x->dpy, view->x->gc,
		     view->pixels[COLOR_WHITE]);
    }

    if (top > 0)
      XFillRectangle(view->x->dpy, pm, view->x->gc,
		     0, 0, view->w_width, top);
    if (bottom < view->w_height)
      XFillRectangle(view->x->dpy, pm, view->x->gc,
		     0, bottom, view->w_width,
		     view->w_height - bottom);
    if (left > 0)
      XFillRectangle(view->x->dpy, pm, view->x->gc,
		     0, top, left, bottom - top);
    if (right < view->w_width)
      XFillRectangle(view->x->dpy, pm, view->x->gc,
		     right, top, view->w_width - right, bottom - top);
  }
}


char CursorDashes[] = { 4, 4 };

void
DrawPending(SimView *view)
{
  Pixmap pm = view->pixmap2;
  int left = (view->w_width / 2) - view->pan_x;
  int top = (view->w_height / 2) - view->pan_y;
  int x, y, size;
  char *iconname = NULL;

  x = (PendingX - toolOffset[PendingTool]) <<4;
  y = (PendingY - toolOffset[PendingTool]) <<4;
  size = toolSize[PendingTool] <<4;
  x += left; y += top;

  XSetStipple(view->x->dpy, view->x->gc, view->x->gray50_stipple);
  XSetTSOrigin(view->x->dpy, view->x->gc, 0, 0);
  XSetForeground(view->x->dpy, view->x->gc, view->x->pixels[COLOR_BLACK]);
  XSetFillStyle(view->x->dpy, view->x->gc, FillStippled);
  XFillRectangle(view->x->dpy, pm, view->x->gc,
		 x, y, size, size);
  XSetFillStyle(view->x->dpy, view->x->gc, FillSolid);

  switch (PendingTool) {
  case residentialState:
    iconname = "@images/res.xpm"; break;
  case commercialState:
    iconname = "@images/com.xpm"; break;
  case industrialState:
    iconname = "@images/ind.xpm"; break;
  case fireState:
    iconname = "@images/fire.xpm"; break;
  case policeState:
    iconname = "@images/police.xpm"; break;
  case stadiumState:
    iconname = "@images/stadium.xpm"; break;
  case seaportState:
    iconname = "@images/seaport.xpm"; break;
  case powerState:
    iconname = "@images/coal.xpm"; break;
  case nuclearState:
    iconname = "@images/nuclear.xpm"; break;
  case airportState:
    iconname = "@images/airport.xpm"; break;
  default:
    break;
  }

  if (iconname != NULL) {
    Pixmap icon = Tk_GetPixmap(view->interp, view->tkwin, iconname);
    float f;
    int i;

    gettimeofday(&now_time, NULL);
    f = (2 * now_time.tv_usec / 1000000.0);
    if (f > 1.0) f = 2.0 - f;
    i = (int)(f * BobHeight * (Players - Votes));

    if (icon != None) {
      XCopyArea(view->x->dpy, icon, pm, view->x->gc, 
		0, 0, size, size, x + i, y - i);
    }
  }
}


void
DrawCursor(SimView *view)
{
  Pixmap pm = Tk_WindowId(view->tkwin);
  int left = (view->w_width / 2) - view->pan_x;
  int top = (view->w_height / 2) - view->pan_y;
  int x, y, mode, size, offset, fg, bg, light, dark;
  SimView *v;

  for (v = sim->editor; v != NULL; v = v->next) {
    mode = v->tool_mode;
    if ((v->show_me != 0) &&
	((mode == -1) || v->tool_showing)) {
      x = v->tool_x; y = v->tool_y;
      if (mode == -1) { /* pan cursor */

	x += left; y += top;

	XSetLineAttributes(view->x->dpy, view->x->gc, 3,
			   LineSolid, CapRound, JoinMiter);
	XSetForeground(view->x->dpy, view->x->gc,
		       view->pixels[COLOR_BLACK]);
	XDrawLine(view->x->dpy, pm, view->x->gc,
		  x - 6, y - 6, x + 6, y + 6);
	XDrawLine(view->x->dpy, pm, view->x->gc,
		  x - 6, y + 6, x + 6, y - 6);
	XDrawLine(view->x->dpy, pm, view->x->gc,
		  x - 8, y, x + 8, y);
	XDrawLine(view->x->dpy, pm, view->x->gc,
		  x, y + 8, x, y - 8);
	XSetLineAttributes(view->x->dpy, view->x->gc, 1,
			   LineSolid, CapRound, JoinMiter);
	XSetForeground(view->x->dpy, view->x->gc,
		       view->pixels[COLOR_WHITE]);
	XDrawLine(view->x->dpy, pm, view->x->gc,
		  x - 6, y - 6, x + 6, y + 6);
	XDrawLine(view->x->dpy, pm, view->x->gc,
		  x - 6, y + 6, x + 6, y - 6);
	XDrawLine(view->x->dpy, pm, view->x->gc,
		  x - 8, y, x + 8, y);
	XDrawLine(view->x->dpy, pm, view->x->gc,
		  x, y + 8, x, y - 8);
	XSetLineAttributes(view->x->dpy, view->x->gc, 1,
			   LineSolid, CapButt, JoinMiter);

      } else { /* edit cursor */

	size = toolSize[v->tool_state];
	fg = toolColors[v->tool_state] & 0xff;
	light = COLOR_WHITE;
	dark = COLOR_BLACK;
	if (mode == 1) {
	  int temp = dark;
	  dark = light;
	  light = temp;
	}
	switch (v->tool_state) {

	case chalkState:
	  x += left; y += top;
	  if (mode == 1) {
	    offset = 2;
	  } else {
	    offset = 0;

	    if (view->x->color) {
	      XSetForeground(view->x->dpy, view->x->gc,
			     view->pixels[COLOR_MEDIUMGRAY]);
	      XFillArc(view->x->dpy, pm, view->x->gc,
		       x - 8, y + 7, 7, 7, 0, 360 * 64);
	    } else {
	      XSetStipple(view->x->dpy, view->x->gc,
			  view->x->gray50_stipple);
	      XSetTSOrigin(view->x->dpy, view->x->gc, 0, 0);
	      XSetForeground(view->x->dpy, view->x->gc,
			     view->x->pixels[COLOR_BLACK]);
	      XSetBackground(view->x->dpy, view->x->gc,
			     view->x->pixels[COLOR_WHITE]);
	      XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled);
	      XFillArc(view->x->dpy, pm, view->x->gc,
		       x - 8, y + 7, 7, 7, 0, 360 * 64);
	      XSetFillStyle(view->x->dpy, view->x->gc, FillSolid);
	    }
	  }

	  if (view->x->color) {
	    XSetLineAttributes(view->x->dpy, view->x->gc, 3,
			       LineSolid, CapRound, JoinMiter);
	    XSetForeground(view->x->dpy, view->x->gc,
			   view->pixels[COLOR_LIGHTGRAY]);
	    XFillArc(view->x->dpy, pm, view->x->gc,
		     x - 6 - offset, y + 5 + offset, 7, 7, 0, 360 * 64);
	    XDrawLine(view->x->dpy, pm, view->x->gc,
		      x + 13 - offset, y - 5 + offset,
		      x - 1 - offset, y + 9 + offset);
	    XSetForeground(view->x->dpy, view->x->gc,
			   view->pixels[COLOR_WHITE]);
	    XDrawLine(view->x->dpy, pm, view->x->gc,
		      x + 11 - offset, y - 7 + offset,
		      x - 3 - offset, y + 7 + offset);
	    XFillArc(view->x->dpy, pm, view->x->gc,
		     x + 8 - offset, y - 9 + offset, 7, 7, 0, 360 * 64);
	    XSetLineAttributes(view->x->dpy, view->x->gc, 1,
			       LineSolid, CapButt, JoinMiter);
	  } else {
	    XSetLineAttributes(view->x->dpy, view->x->gc, 3,
			       LineSolid, CapRound, JoinMiter);
	    XSetStipple(view->x->dpy, view->x->gc,
			view->x->gray25_stipple);
	    XSetTSOrigin(view->x->dpy, view->x->gc, 0, 0);
	    XSetForeground(view->x->dpy, view->x->gc,
			   view->x->pixels[COLOR_BLACK]);
	    XSetBackground(view->x->dpy, view->x->gc,
			   view->x->pixels[COLOR_WHITE]);
	    XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled);
	    XFillArc(view->x->dpy, pm, view->x->gc,
		     x - 6 - offset, y + 5 + offset, 7, 7, 0, 360 * 64);
	    XDrawLine(view->x->dpy, pm, view->x->gc,
		      x + 13 - offset, y - 5 + offset,
		      x - 1 - offset, y + 9 + offset);
	    XSetStipple(view->x->dpy, view->x->gc,
			view->x->gray75_stipple);
	    XDrawLine(view->x->dpy, pm, view->x->gc,
		      x + 11 - offset, y - 7 + offset,
		      x - 3 - offset, y + 7 + offset);
	    XFillArc(view->x->dpy, pm, view->x->gc,
		     x + 8 - offset, y - 9 + offset, 7, 7, 0, 360 * 64);
	    XSetLineAttributes(view->x->dpy, view->x->gc, 1,
			       LineSolid, CapButt, JoinMiter);
	    XSetFillStyle(view->x->dpy, view->x->gc, FillSolid);
	  }

	  break;

	case eraserState:
	  x += left; y += top;
	  if (mode == 1) {
	    offset = 0;
	  } else {
	    offset = 2;

	    if (view->x->color) {
	      XSetForeground(view->x->dpy, view->x->gc,
			     view->pixels[COLOR_MEDIUMGRAY]);
	      XFillRectangle(view->x->dpy, pm, view->x->gc,
		       x - 8, y - 8, 16, 16);
	    } else {
	      XSetStipple(view->x->dpy, view->x->gc,
			  view->x->gray50_stipple);
	      XSetTSOrigin(view->x->dpy, view->x->gc, 0, 0);
	      XSetForeground(view->x->dpy, view->x->gc,
			     view->x->pixels[COLOR_BLACK]);
	      XSetBackground(view->x->dpy, view->x->gc,
			     view->x->pixels[COLOR_WHITE]);
	      XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled);
	      XFillRectangle(view->x->dpy, pm, view->x->gc,
		       x - 8, y - 8, 16, 16);
	      XSetFillStyle(view->x->dpy, view->x->gc, FillSolid);
	    }
	  }

	  if (view->x->color) {
	    XSetForeground(view->x->dpy, view->x->gc,
			   view->pixels[COLOR_LIGHTGRAY]);
	  } else {
	    XSetStipple(view->x->dpy, view->x->gc,
			view->x->gray75_stipple);
	    XSetTSOrigin(view->x->dpy, view->x->gc, 0, 0);
	    XSetForeground(view->x->dpy, view->x->gc,
			   view->x->pixels[COLOR_BLACK]);
	    XSetBackground(view->x->dpy, view->x->gc,
			   view->x->pixels[COLOR_WHITE]);
	    XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled);
	  }

	  /* top */
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 8 + offset, y - 8 - offset,
		    x + 8 + offset, y - 8 - offset);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 7 + offset, y - 7 - offset,
		    x + 7 + offset, y - 7 - offset);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 6 + offset, y - 6 - offset,
		    x + 6 + offset, y - 6 - offset);

	  /* left */
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 8 + offset, y - 8 - offset,
		    x - 8 + offset, y + 8 - offset);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 7 + offset, y - 7 - offset,
		    x - 7 + offset, y + 7 - offset);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 6 + offset, y - 6 - offset,
		    x - 6 + offset, y + 6 - offset);

	  if (view->x->color) {
	    XSetForeground(view->x->dpy, view->x->gc,
			   view->pixels[COLOR_BLACK]);
	  } else {
	    XSetFillStyle(view->x->dpy, view->x->gc, FillSolid);
	  }

	  /* bottom */
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 7 + offset, y + 7 - offset,
		    x + 8 + offset, y + 7 - offset);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 6 + offset, y + 6 - offset,
		    x + 7 + offset, y + 6 - offset);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 5 + offset, y + 5 - offset,
		    x + 6 + offset, y + 5 - offset);

	  /* right */
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x + 7 + offset, y + 8 - offset,
		    x + 7 + offset, y - 7 - offset);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x + 6 + offset, y + 7 - offset,
		    x + 6 + offset, y - 6 - offset);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x + 5 + offset, y + 6 - offset,
		    x + 5 + offset, y - 5 - offset);

	  if (view->x->color) {
	    XSetForeground(view->x->dpy, view->x->gc,
			   view->pixels[COLOR_DARKGRAY]);
	    XFillRectangle(view->x->dpy, pm, view->x->gc,
			   x - 5 + offset, y - 5 - offset, 10, 10);
	  } else {
	    XSetStipple(view->x->dpy, view->x->gc,
			view->x->gray50_stipple);
	    XSetForeground(view->x->dpy, view->x->gc,
			   view->x->pixels[COLOR_BLACK]);
	    XSetBackground(view->x->dpy, view->x->gc,
			   view->x->pixels[COLOR_WHITE]);
	    XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled);
	    XFillRectangle(view->x->dpy, pm, view->x->gc,
			   x - 5 + offset, y - 5 - offset, 10, 10);
	    XSetFillStyle(view->x->dpy, view->x->gc, FillSolid);
	  }

	  break;

	default:
	  offset = toolOffset[v->tool_state];

	  bg = (toolColors[v->tool_state] >> 8) & 0xff;

	  x = (x & ~15) - (offset <<4);
	  y = (y & ~15) - (offset <<4);
	  size <<= 4;
	  x += left; y += top;

	  XSetForeground(view->x->dpy, view->x->gc,
			 view->pixels[dark]);
	  XDrawRectangle(view->x->dpy, pm, view->x->gc,
			 x - 1, y - 1, size + 4, size + 4);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 3, y + size + 3,
		    x - 1, y + size + 3);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x + size + 3, y - 3,
		    x + size + 3, y - 1);

	  XSetForeground(view->x->dpy, view->x->gc,
			 view->pixels[light]);
	  XDrawRectangle(view->x->dpy, pm, view->x->gc,
			 x - 4, y - 4, size + 4, size + 4);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 4, y + size + 1,
		    x - 4, y + size + 3);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x + size + 1, y - 4,
		    x + size + 3, y - 4);

	  if (view->x->color) {
	    if (fg == bg) {
	      XSetForeground(view->x->dpy, view->x->gc,
			     view->x->pixels[fg]);
	      XSetLineAttributes(view->x->dpy, view->x->gc, 2,
				 LineSolid, CapButt, JoinMiter);
	    } else {
	      XSetForeground(view->x->dpy, view->x->gc,
			     view->x->pixels[fg]);
	      XSetBackground(view->x->dpy, view->x->gc,
			     view->pixels[bg]);

	      XSetLineAttributes(view->x->dpy, view->x->gc, 2,
				 LineDoubleDash, CapButt, JoinMiter);
	      XSetDashes(view->x->dpy, view->x->gc, 0, CursorDashes, 2);
	    }
	  } else {
	    XSetStipple(view->x->dpy, view->x->gc,
			view->x->gray50_stipple);
	    XSetForeground(view->x->dpy, view->x->gc,
			   view->x->pixels[COLOR_BLACK]);
	    XSetBackground(view->x->dpy, view->x->gc,
			   view->x->pixels[COLOR_WHITE]);
	    XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled);
	    XSetLineAttributes(view->x->dpy, view->x->gc, 2,
			       LineSolid, CapButt, JoinMiter);
	  }

	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 2, y - 1, x - 2, y + size + 3);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x - 1, y + size + 2, x + size + 3, y + size + 2);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x + size + 2, y + size + 1, x + size + 2, y - 3);
	  XDrawLine(view->x->dpy, pm, view->x->gc,
		    x + size + 1, y - 2, x - 3, y - 2);

	  if (!view->x->color) {
	    XSetFillStyle(view->x->dpy, view->x->gc, FillSolid);
	  }
	  XSetLineAttributes(view->x->dpy, view->x->gc, 1,
			     LineSolid, CapButt, JoinMiter);
	  
	  break;
	}
      }
    }
  }
}


void
TimeElapsed(struct timeval *elapsed,
	    struct timeval *start,
	    struct timeval *finish)
{
  int usec = finish->tv_usec - start->tv_usec;
  int sec = finish->tv_sec - start->tv_sec;

  while (usec < 0) {
    usec += 1000000;
    sec--;
  }
  elapsed->tv_usec = usec;
  elapsed->tv_sec = sec;
}



void
DrawOverlay(SimView *view)
{
  int width = view->w_width;
  int height = view->w_height;
  int left = view->pan_x - (width / 2);
  int top = view->pan_y - (height / 2);
  int right = left + width;
  int bottom = top + height;
  int showing = 0;
  Ink *ink;
  struct timeval start, finished, elapsed;

  for (ink = sim->overlay; ink != NULL; ink = ink->next) {
    if ((ink->bottom >= top) && (ink->top <= bottom) &&
	(ink->right >= left) && (ink->left <= right)) {
      showing = 1;
      break;
    }
  }

  if (!showing) return;

/* overlay_mode state machine:
   0 => overlay invalid: 
        draw lines to pm => 1
   1 => overlay stable: 
        sync, time draw lines to pm => 2
   2 => overlay stable: 
        draw lines to ol,
        sync, time clip ol to pm,
        lines faster? => 3,
	clipping faster? => 4
   3 => lines faster: 
        draw lines to pm => 3
   4 => clipping faster: 
        clip ol to pm => 4
*/   

  switch (view->overlay_mode) {
  case 0:
    DrawTheOverlay(view, view->x->gc,
		   view->pixmap2, view->pixels[COLOR_WHITE],
		   top, bottom, left, right, 0);
    view->overlay_mode = 1;
    break;
  case 1:
    XSync(view->x->dpy, False);
    gettimeofday(&start, NULL);
    DrawTheOverlay(view, view->x->gc,
		   view->pixmap2, view->pixels[COLOR_WHITE],
		   top, bottom, left, right, 0);
    XSync(view->x->dpy, False);
    gettimeofday(&finished, NULL);
    TimeElapsed(&view->overlay_time, &start, &finished);
    view->overlay_mode = 2;
    break;
  case 2:
    XSetForeground(view->x->dpy, view->x->overlay_gc, 0);
    XFillRectangle(view->x->dpy, view->overlay_pixmap, view->x->overlay_gc,
		   0, 0, view->m_width, view->m_height);
    DrawTheOverlay(view, view->x->overlay_gc,
		   view->overlay_pixmap, 1,
		   top, bottom, left, right, 1);
    XSync(view->x->dpy, False);
    gettimeofday(&start, NULL);
    ClipTheOverlay(view);
    XSync(view->x->dpy, False);
    gettimeofday(&finished, NULL);
    TimeElapsed(&elapsed, &start, &finished);
    if ((elapsed.tv_sec > view->overlay_time.tv_sec) ||
	((elapsed.tv_sec == view->overlay_time.tv_sec) &&
	 ((elapsed.tv_usec > view->overlay_time.tv_usec)))) {
      view->overlay_mode = 3;
    } else {
      view->overlay_mode = 4;
    }
    break;
  case 3:
    DrawTheOverlay(view, view->x->gc,
		   view->pixmap2, view->pixels[COLOR_WHITE],
		   top, bottom, left, right, 0);
    break;
  case 4:
    ClipTheOverlay(view);
    break;
  }
}


void
DrawTheOverlay(SimView *view, GC gc, Pixmap pm, int color, 
	       int top, int bottom, int left, int right,
	       int onoverlay)
{
  Ink *ink;

  if (view->x->color) {
    XSetForeground(view->x->dpy, gc, color);
    XSetLineAttributes(view->x->dpy, gc, 3,
		       LineSolid, CapButt, JoinBevel);
  } else {
    if (!onoverlay) {
      XSetStipple(view->x->dpy, gc, view->x->gray50_stipple);
      XSetTSOrigin(view->x->dpy, gc, view->updates & 1, 0);
      XSetBackground(view->x->dpy, gc, 0);
      XSetFillStyle(view->x->dpy, gc, FillOpaqueStippled);
    }
    XSetForeground(view->x->dpy, gc, 1);
    XSetLineAttributes(view->x->dpy, gc, 3,
		       LineSolid, CapButt, JoinBevel);
  }
  for (ink = sim->overlay; ink != NULL; ink = ink->next) {
    if ((ink->bottom >= top) && (ink->top <= bottom) &&
	(ink->right >= left) && (ink->left <= right)) {
      if (ink->length <= 1) {
	XFillArc(view->x->dpy, pm, gc,
		 ink->x - 3, ink->y - 3, 6, 6, 0, 360 * 64);
      } else {
	ink->points[0].x = ink->x - left;
	ink->points[0].y = ink->y - top;
	XDrawLines(view->x->dpy, pm, gc,
		   ink->points, ink->length, CoordModePrevious);
      }
    }
  }
  if (!view->x->color) {
    XSetFillStyle(view->x->dpy, gc, FillSolid);
  }
  XSetLineAttributes(view->x->dpy, gc, 1,
		     LineSolid, CapButt, JoinMiter);
}


void
ClipTheOverlay(SimView *view)
{
  if (view->x->color) {
    XSetForeground(view->x->dpy, view->x->gc, view->pixels[COLOR_WHITE]);
    XSetFillStyle(view->x->dpy, view->x->gc, FillStippled);
    XSetStipple(view->x->dpy, view->x->gc, view->overlay_pixmap);
    XSetTSOrigin(view->x->dpy, view->x->gc, 0, 0);
    XFillRectangle(view->x->dpy, view->pixmap2, view->x->gc,
		   0, 0, view->w_width, view->w_height);
    XSetFillStyle(view->x->dpy, view->x->gc, FillSolid);
  } else {
    XSetStipple(view->x->dpy, view->x->gc, view->x->gray50_stipple);
    XSetTSOrigin(view->x->dpy, view->x->gc, view->updates & 1, 0);
    XSetForeground(view->x->dpy, view->x->gc, view->pixels[COLOR_WHITE]);
    XSetBackground(view->x->dpy, view->x->gc, view->pixels[COLOR_BLACK]);
    XSetFillStyle(view->x->dpy, view->x->gc, FillOpaqueStippled);
    XSetLineAttributes(view->x->dpy, view->x->gc, 3,
		       LineSolid, CapButt, JoinBevel);
    XSetClipOrigin(view->x->dpy, view->x->gc, 0, 0);
    XSetClipMask(view->x->dpy, view->x->gc, view->overlay_pixmap);
    XFillRectangle(view->x->dpy, view->pixmap2, view->x->gc,
		   0, 0, view->w_width, view->w_height);
    XSetFillStyle(view->x->dpy, view->x->gc, FillSolid);
    XSetClipMask(view->x->dpy, view->x->gc, None);
  }
}
