/*----------------------------------------------------------------------------*
 | This file is part of DEU (Doom Editing Utilities), created by the DEU team:|
 | Raphael Quinet, Brendon Wyber, Ted Vessenes and others.  See README.1ST or |
 | the "about" dialog box for full credits.                                   |
 |                                                                            |
 | DEU is an open project: if you think that you can contribute, please join  |
 | the DEU team.  You will be credited for any code (or ideas) included in    |
 | the next version of the program.                                           |
 |                                                                            |
 | If you want to make any modifications and re-distribute them on your own,  |
 | you must follow the conditions of the DEU license.  Read the file LICENSE  |
 | in this directory or README.1ST in the top directory.  If do not have a    |
 | copy of these files, you can request them from any member of the DEU team, |
 | or by mail: Raphael Quinet, Rue des Martyrs 9, B-4550 Nandrin (Belgium).   |
 |                                                                            |
 | This program comes with absolutely no warranty.  Use it at your own risks! |
 *----------------------------------------------------------------------------*

 M_EDIT.C - The main loop of the map editor

*/

/* the includes */
#include "deu.h"
#include <math.h>
#ifdef DEU_UNIX
#include <unistd.h>
#endif
#include "d_main.h"
#include "d_misc.h"
#include "d_config.h"
#include "d_wads.h"
#include "g_gfx.h"
#include "g_mouse.h"
#include "w_levels.h"
#include "w_names.h"
#include "w_things.h"
#include "w_object.h"
#include "w_select.h"
#include "w_cutpas.h"
#include "i_menus.h"
#include "m_checks.h"
#include "m_object.h"
#include "m_edmenu.h"
#include "m_edobj.h"
#include "m_info.h"
#include "m_print.h"
#include "m_mapdrw.h"
#include "m_edit.h"

/* pointer modes */
#define PM_NORMAL    0            /* normal pointer mode */
#define PM_BOXSELECT 1            /* selection box active */
#define PM_DRAG      2            /* drag mode */
#define PM_LINEDRAW  3            /* "quick draw" mode */
#define PM_BOXCREATE 4            /* sector creation mode (box) */
#define PM_THINGROT  5            /* thing rotate mode (orientation) */

/* global variables */
LevelPtr level_clipboard = NULL;  /* clipboard for cut, copy & paste */

/* private */
static int   PointerMode;         /* current pointer mode: see PM_* symbols */
static Int16 CurObject = -1;      /* object under the pointer */
static Int16 OldObject = -1;      /* previous value of CurObject */
static Int16 RefPointX = 0;       /* X coord of reference point (sel. box) */
static Int16 RefPointY = 0;       /* Y coord of reference point (sel. box) */
static Int16 RefVertex = -1;      /* reference vertex for line draw mode */
static Int16 OldPointerX = 0;     /* previous X coord of pointer */
static Int16 OldPointerY = 0;     /* previous Y coord of pointer */
static int   MoveSpeed = 20;      /* speed of pointer movement (keyboard) */
static int   MoveSpeedInc = 0;    /* used for dynamic pointer acceleration */

#ifndef NEW_CODE
static MapInfoPtr xxx_info;       /* global pointer for the info relative to
                                     the map editor window - will be discarded
                                     when multiple windows are used. */
static Bool       xxx_exit;       /* set to TRUE when the map editor window
                                     has to be closed - will be discarded
                                     when multiple windows are used. */
#define XXX_NO_WINDOWS 0
#endif


/*
   Select a map name.
   (the map name points to a static area ovewritten after each call)
*/

static char *SelectMapName(char *mapname, Bool IWADLevelsOnly)
{
  MDirPtr       dir;
  static char   name[9];
  char        **levels = NULL;
  int           numlevels;

  /* If IWADLevelsOnly is TRUE, only the map names that are present in
     the main WAD file will be given in the list.  It should always be
     TRUE when saving a file, and FALSE when loading.
     If a map name exists in a PWAD but not in the IWAD, this means that
     the PWAD was designed for another version of Doom.  DEU should not
     allow users to save a WAD for a version of Doom that they don't have,
     so this is what IWADLevelsOnly is for...
  */
  /*! IWADLevelsOnly is not used yet.  The main dir should be removed first. */
  if (mapname != NULL)
    strncpy(name, mapname, 9);
  else
    name[0] = '\0';
  numlevels = 0;
  for (dir = MasterDir; dir; dir = dir->next)
    {
      if (dir->dir.size == 0 && (( dir->dir.name[0] == 'E'
                                 && dir->dir.name[2] == 'M'
                                 && dir->dir.name[4] == '\0')
                                || (  dir->dir.name[0] == 'M'
                                    && dir->dir.name[1] == 'A'
                                    && dir->dir.name[2] == 'P'
                                    && dir->dir.name[5] == '\0')) )
        {
          /* if the proposed map name exists, return directly */
          if (!stricmp(name, dir->dir.name))
            {
              if (levels != NULL)
                FreeMemory(levels);
              return name;
            }
          if (numlevels == 0)
            levels = (char **)GetMemory(sizeof(char *));
          else
            levels = (char **)ResizeMemory(levels, (numlevels + 1) * sizeof(char *));
          levels[numlevels] = dir->dir.name;
          numlevels++;
        }
    }
  if (numlevels == 0)
    ProgError("No maps found in the WAD file(s)");
  if (mapname == NULL)
    strncpy(name, levels[0], 9);
  InputNameFromList(-1, -1, "Select a map to edit:", numlevels, levels, name);
  FreeMemory(levels);
  if (name[0] != '\0')
    return name;
  else
    return NULL;
}



/*
   Get the name of the new WAD file (when saving).
   (the file name should be freed after use)
*/

static char *GetNewWadFileName(char *mapname, char *oldfilename)
{
  char   *newfilename;
  char   *dotp;
  WadPtr  wad;

  /* get the file name */
  newfilename = (char *)GetMemory(80); /*! check size (oldfilename > 80)? */
  if (oldfilename == NULL || !strcmp(oldfilename, Config.mainWad))
    {
      if (mapname == NULL)
        strcpy(newfilename, "noname");
      else
        strcpy(newfilename, mapname);
    }
  else
    strcpy(newfilename, oldfilename);
  /* remove the extension */
  dotp = GetFileExtension(newfilename);
  if (dotp != NULL && *dotp != '\0')
    *(dotp - 1) = '\0';
  /* let the user edit the name */
  do
    {
      InputFileName(-1, -1, "Name of the new file (*.WAD):", 79, newfilename);
    }
  while (!strcmp(newfilename, Config.mainWad));
  /* abort if the user pressed Esc */
  if (*newfilename == '\0')
    {
      FreeMemory(newfilename);
      return NULL;
    }
  /* add a .WAD extension if needed */
  dotp = GetFileExtension(newfilename);
  if (dotp == NULL || *dotp == '\0')
    strcat(newfilename, ".wad");
  /* if the WAD file already exists, rename it to "*.BAK" */
  for (wad = WadFileList; wad; wad = wad->next)
    if (!stricmp(newfilename, wad->filename))
      {
        dotp = GetFileExtension(wad->filename);
        if (dotp == NULL || *dotp == '\0')
          strcat(wad->filename, ".BAK");
        else
          strcpy(dotp - 1, ".BAK");
        /* need to close, then reopen: problems with SHARE.EXE */
        /*! this problem will disappear if the WADs are closed by default */
        fclose(wad->fileinfo);
        if (rename(newfilename, wad->filename) < 0)
          {
            if (unlink(wad->filename) < 0)
              ProgError("could not delete file \"%s\"", wad->filename);
            if (rename(newfilename, wad->filename) < 0)
              ProgError("could not rename \"%s\" to \"%s\"", newfilename, wad->filename);
          }
        wad->fileinfo = fopen(wad->filename, "rb");
        if (wad->fileinfo == NULL)
          ProgError("could not reopen file \"%s\"", wad->filename);
        break;
      }
  return newfilename;
}



/*
   Restore the pointer mode to normal.
*/

static Bool PointerModeAbort(MapInfoPtr map_info)
{
  Bool redraw;

  switch (PointerMode)
    {
    case PM_NORMAL:
    case PM_DRAG:
      redraw = FALSE;
      break;
    case PM_BOXSELECT:
      redraw = TRUE;
      break;
    case PM_LINEDRAW:
      if (RefVertex >= 0)
        {
          /* erase the old line */
          SetLineDrawingMode(DRAW_XOR);
          SetLinePatternAndWidth(DASHED_PATTERN, 1);
          SetColor(YELLOW);
          DrawScreenLine(SCREENX(RefPointX),
                         SCREENY(RefPointY),
                         OldPointerX,
                         OldPointerY);
          SetLinePatternAndWidth(SOLID_PATTERN, 1);
          SetLineDrawingMode(DRAW_NORMAL);
        }
      redraw = FALSE;
      break;
    case PM_BOXCREATE:
      redraw = FALSE;
      /*! ... */
      break;
    case PM_THINGROT:
      redraw = FALSE;
      /*! ... */
      break;
    }
  PointerMode = PM_NORMAL;
  return redraw;
}


/*
   Re-highlight the objects for the current pointer mode (after the map
   has been redrawn).
*/

static void PointerModeRedraw(MapInfoPtr map_info)
{
  SelPtr cur;
  Int16  x, y;

  x = SCREENX(RefPointX);
  y = SCREENY(RefPointY);
  switch (PointerMode)
    {
    case PM_NORMAL:
      for (cur = map_info->selected; cur; cur = cur->next)
        HighlightObject(map_info->level, map_info->edit_mode,
                        cur->objnum, GREEN);
      if (CurObject >= 0)
        HighlightObject(map_info->level, map_info->edit_mode,
                        CurObject, YELLOW);
      break;
    case PM_DRAG:
      break;
    case PM_BOXSELECT:
      SetLineDrawingMode(DRAW_XOR);
      SetLinePatternAndWidth(DASHED_PATTERN, 1);
      SetColor(CYAN);
      DrawScreenRectangle(x, y, PointerX, PointerY);
      SetLinePatternAndWidth(SOLID_PATTERN, 1);
      SetLineDrawingMode(DRAW_NORMAL);
      break;
    case PM_LINEDRAW:
      SetLineDrawingMode(DRAW_XOR);
      SetLinePatternAndWidth(DASHED_PATTERN, 1);
      SetColor(YELLOW);
      DrawScreenLine(x, y, PointerX, PointerY);
      SetLinePatternAndWidth(SOLID_PATTERN, 1);
      SetLineDrawingMode(DRAW_NORMAL);
      break;
    case PM_BOXCREATE:
      /*! ... */
      break;
    case PM_THINGROT:
      /*! ... */
      break;
    }
}


/*
   Start Drag mode (selected objects move with the pointer).
*/

static void DragModeStart(MapInfoPtr map_info)
{
  SelPtr tmp_sel;

  if (CurObject < 0)
    return;
  PointerMode = PM_DRAG;
  if (IsSelected(map_info->selected, CurObject) == FALSE)
    ForgetSelection(&(map_info->selected));
  tmp_sel = map_info->selected;
  if (tmp_sel == NULL)
    SelectObject(&tmp_sel, CurObject);
  else if (tmp_sel->objnum != CurObject)
    {
      /* current object must be first in the list */
      UnSelectObject(&tmp_sel, CurObject);
      SelectObject(&tmp_sel, CurObject);
    }
  /* initialise the internal variables in MoveObjectsToCoords */
  if (map_info->edit_mode == OBJ_THINGS)
    MoveObjectsToCoords(map_info->level, OBJ_THINGS,
                        tmp_sel,
                        map_info->level->things[CurObject].xpos,
                        map_info->level->things[CurObject].ypos,
                        0);
  else if (map_info->edit_mode == OBJ_VERTEXES)
    MoveObjectsToCoords(map_info->level, OBJ_VERTEXES,
                        tmp_sel,
                        map_info->level->vertexes[CurObject].x,
                        map_info->level->vertexes[CurObject].y,
                        0);
  else
    MoveObjectsToCoords(map_info->level, map_info->edit_mode,
                        tmp_sel,
                        MAPX(PointerX),
                        MAPY(PointerY),
                        map_info->grid_scale);
  if (map_info->selected == NULL)
    ForgetSelection(&tmp_sel);
}


/*
   End Drag mode (drop the objects and check if they overlap).
   Returns TRUE if the map has to be redrawn.
*/

static Bool DragModeEnd(MapInfoPtr map_info)
{
  Bool   redraw_map;
  SelPtr tmp_sel, cur;
  LDPtr  ldptr;
  UInt16 ld;
  Int16  sd;

  PointerMode = PM_NORMAL;
  if (CurObject < 0)
    return FALSE;
  switch (map_info->edit_mode)
    {
    case OBJ_VERTEXES:
      tmp_sel = map_info->selected;
      if (tmp_sel == NULL)
        SelectObject(&tmp_sel, CurObject);
      redraw_map = AutoMergeVertices(map_info->level, &tmp_sel);
      if (map_info->selected == NULL)
        ForgetSelection(&tmp_sel);
      else
        map_info->selected = tmp_sel;
      break;
    case OBJ_LINEDEFS:
      tmp_sel = NULL;
      if (map_info->selected == NULL)
        {
          ldptr = &(map_info->level->linedefs[CurObject]);
          SelectObject(&tmp_sel, ldptr->start);
          SelectObject(&tmp_sel, ldptr->end);
        }
      else
        {
          for (cur = map_info->selected; cur; cur = cur->next)
            {
              ldptr = &(map_info->level->linedefs[cur->objnum]);
              if (!IsSelected(tmp_sel, ldptr->start))
                SelectObject(&tmp_sel, ldptr->start);
              if (!IsSelected(tmp_sel, ldptr->end))
                SelectObject(&tmp_sel, ldptr->end);
            }
        }
      ld = map_info->level->num_linedefs;
      redraw_map = AutoMergeVertices(map_info->level, &tmp_sel);
      ForgetSelection(&tmp_sel);
      if (map_info->level->num_linedefs != ld)
        ForgetSelection(&(map_info->selected)); /* kludge */
      break;
    case OBJ_SECTORS:
      tmp_sel = NULL;
      ldptr = map_info->level->linedefs;
      for (ld = map_info->level->num_linedefs; ld; ld--)
        {
          sd = ldptr->sidedef1;
          if (sd > 0 && IsSelected(map_info->selected,
                                   map_info->level->sidedefs[sd].sector))
            {
              if (!IsSelected(tmp_sel, ldptr->start))
                SelectObject(&tmp_sel, ldptr->start);
              if (!IsSelected(tmp_sel, ldptr->end))
                SelectObject(&tmp_sel, ldptr->end);
            }
          else
            {
              sd = ldptr->sidedef2;
              if (sd > 0 && IsSelected(map_info->selected,
                                       map_info->level->sidedefs[sd].sector))
                {
                  if (!IsSelected(tmp_sel, ldptr->start))
                    SelectObject(&tmp_sel, ldptr->start);
                  if (!IsSelected(tmp_sel, ldptr->end))
                    SelectObject(&tmp_sel, ldptr->end);
                }
            }
#ifdef BUGGY_TURBOC_3
          ldptr = ldptr + 1;
#else
          ldptr++;
#endif
        }
      redraw_map = AutoMergeVertices(map_info->level, &tmp_sel);
      ForgetSelection(&tmp_sel);
      /* the number of Sectors doesn't change, so map_info->selected is OK */
      break;
    default:
      redraw_map = FALSE;
    }
  if (redraw_map == FALSE)
    PointerModeRedraw(map_info);
  return redraw_map;
}


/*
   Pointer moved in Drag mode (move the objects on the map).
   Returns TRUE if the map has to be redrawn.
*/

static Bool DragModeMove(MapInfoPtr map_info)
{
  return MoveObjectsToCoords(map_info->level, map_info->edit_mode,
                             NULL, /* the list of object is already known */
                             MAPX(PointerX),
                             MAPY(PointerY),
                             map_info->grid_scale);
}


/*
   Start "stretch selection box" mode.
*/

static void SelBoxModeStart(MapInfoPtr map_info)
{
  RefPointX = MAPX(PointerX);
  RefPointY = MAPY(PointerY);
  PointerMode = PM_BOXSELECT;
  PointerModeRedraw(map_info);
}


/*
   End box select: select all objects in the selection box.
   Returns TRUE if the map has to be redrawn.
*/

static Bool SelBoxModeEnd(MapInfoPtr map_info)
{
  SelPtr oldsel;

  PointerMode = PM_NORMAL;
  /* erase the selection box */
  SetLineDrawingMode(DRAW_XOR);
  SetLinePatternAndWidth(DASHED_PATTERN, 1);
  SetColor(CYAN);
  DrawScreenRectangle(SCREENX(RefPointX), SCREENY(RefPointY),
                      OldPointerX, OldPointerY);
  SetLinePatternAndWidth(SOLID_PATTERN, 1);
  SetLineDrawingMode(DRAW_NORMAL);
  /* additive selection box or not? */
  if (Config.additiveSelBox == TRUE)
    oldsel = map_info->selected;
  else
    ForgetSelection(&(map_info->selected));
  map_info->selected = SelectObjectsInBox(map_info->level, map_info->edit_mode,
                                          RefPointX, RefPointY,
                                          MAPX(PointerX), MAPY(PointerY));
  if (Config.additiveSelBox == TRUE)
    while (oldsel != NULL)
      {
        if (! IsSelected(map_info->selected, oldsel->objnum))
          SelectObject(&(map_info->selected), oldsel->objnum);
        UnSelectObject(&oldsel, oldsel->objnum);
      }
  if (map_info->selected)
    {
      CurObject = map_info->selected->objnum;
      PlaySound(440, 10);
    }
  else
    CurObject = -1;
  PointerModeRedraw(map_info);
  return FALSE;
}


/*
   Pointer moved in "box select" mode (change the size of the selection box).
   Returns TRUE if the map has to be redrawn.
*/

static Bool SelBoxModeMove(MapInfoPtr map_info)
{
  Int16 x, y;

  x = SCREENX(RefPointX);
  y = SCREENY(RefPointY);
  SetLineDrawingMode(DRAW_XOR);
  SetLinePatternAndWidth(DASHED_PATTERN, 1);
  SetColor(CYAN);
  /* erase the old box */
  DrawScreenRectangle(x, y, OldPointerX, OldPointerY);
  /* draw the new box */
  DrawScreenRectangle(x, y, PointerX, PointerY);
  SetLinePatternAndWidth(SOLID_PATTERN, 1);
  SetLineDrawingMode(DRAW_NORMAL);
  /* OldPointerX and OldPointerY will be updated by the calling function */
  return FALSE;
}


/*
   Add a new Vertex (and a LineDef) in line draw mode.
*/

static void LineDrawAddVertex(MapInfoPtr map_info)
{
  Int16 ld;

  if (CurObject < 0)
    {
      if (map_info->grid_scale > 0)
        InsertObject(map_info->level, OBJ_VERTEXES, -1,
                     (Int16) ((int)(MAPX(PointerX) + map_info->grid_scale / 2))
                       & ((int)(~(map_info->grid_scale - 1))),
                     (Int16) ((int)(MAPY(PointerY) + map_info->grid_scale / 2))
                       & ((int)(~(map_info->grid_scale - 1))));
      else
        InsertObject(map_info->level, OBJ_VERTEXES, -1,
                     MAPX(PointerX),
                     MAPY(PointerY));
      CurObject = map_info->level->num_vertexes - 1;
    }
  else
    HighlightObject(map_info->level, OBJ_VERTEXES, CurObject, CYAN);
  if (RefVertex >= 0)
    {
      /* erase the old line */
      PointerModeRedraw(map_info);
      /* add a new line between the current vertex and the previous one */
      InsertObject(map_info->level, OBJ_LINEDEFS, -1, 0, 0);
      ld = map_info->level->num_linedefs - 1;
      map_info->level->linedefs[ld].start = RefVertex;
      map_info->level->linedefs[ld].end = CurObject;
      SelectObject(&(map_info->selected), ld);
      /* draw the solid line */
      SetColor(WHITE);
      DrawScreenLine(SCREENX(RefPointX),
                     SCREENY(RefPointY),
                     OldPointerX,
                     OldPointerY);
    }
  RefVertex = CurObject;
  RefPointX = map_info->level->vertexes[RefVertex].x;
  RefPointY = map_info->level->vertexes[RefVertex].y;
  /* draw the new line */
  PointerModeRedraw(map_info);
}


/*
   Start line drawing mode.
*/

static void LineDrawModeStart(MapInfoPtr map_info)
{
  PointerMode = PM_LINEDRAW;
  ForgetSelection(&(map_info->selected));
  RefVertex = -1;
  CurObject = -1;
  LineDrawAddVertex(map_info);
}


/*
   End line drawing mode.
   Returns TRUE if the map has to be redrawn.
*/

static Bool LineDrawModeEnd(MapInfoPtr map_info)
{
  PointerMode = PM_NORMAL;
  if (RefVertex >= 0)
    {
      /* erase the old line */
      SetLineDrawingMode(DRAW_XOR);
      SetLinePatternAndWidth(DASHED_PATTERN, 1);
      SetColor(YELLOW);
      DrawScreenLine(SCREENX(RefPointX),
                     SCREENY(RefPointY),
                     OldPointerX,
                     OldPointerY);
      SetLinePatternAndWidth(SOLID_PATTERN, 1);
      SetLineDrawingMode(DRAW_NORMAL);
    }
  PointerModeRedraw(map_info);
  return FALSE;
}


/*
   Pointer moved in line drawing mode: redraw the line in its new position.
   Returns TRUE if the map has to be redrawn.
*/

static Bool LineDrawModeMove(MapInfoPtr map_info)
{
  Int16 x, y;

  x = SCREENX(RefPointX);
  y = SCREENY(RefPointY);
  SetLineDrawingMode(DRAW_XOR);
  SetLinePatternAndWidth(DASHED_PATTERN, 1);
  SetColor(YELLOW);
  /* erase the old line */
  DrawScreenLine(x, y, OldPointerX, OldPointerY);
  /* draw the new line */
  DrawScreenLine(x, y, PointerX, PointerY);
  SetLinePatternAndWidth(SOLID_PATTERN, 1);
  SetLineDrawingMode(DRAW_NORMAL);
  /* OldPointerX and OldPointerY will be updated by the calling function */
  return FALSE;
}


/*
   Change the edit mode and convert the selection if necessary.
   If direct = TRUE, new_type holds the new object type (new edit mode).
   If direct = FALSE, the editor switches to the next object type or to the
   previous one depending on the sign of new_type.
   The calling function must redraw the map.
*/

static void ChangeEditMode(MapInfoPtr map_info, Bool direct, int new_type)
{
  int    old_mode;
  SelPtr new_sel;

  (void) PointerModeAbort(map_info);
  if (direct == TRUE) /* direct mode change ('T', 'V', 'L', 'S') */
    {
      ForgetSelection(&(map_info->selected));
      map_info->edit_mode = new_type;
    }
  else /* relative change (next or previous) */
    {
      old_mode = map_info->edit_mode;
      if (new_type > 0) /* next mode ('Tab') */
        {
          switch (map_info->edit_mode)
            {
            case OBJ_THINGS:
              map_info->edit_mode = OBJ_VERTEXES;
              break;
            case OBJ_VERTEXES:
              map_info->edit_mode = OBJ_LINEDEFS;
              break;
            case OBJ_LINEDEFS:
              map_info->edit_mode = OBJ_SECTORS;
              break;
            case OBJ_SECTORS:
              map_info->edit_mode = OBJ_THINGS;
              break;
            }
        }
      else /* previous mode ('Shift-Tab') */
        {
          switch (map_info->edit_mode)
            {
            case OBJ_THINGS:
              map_info->edit_mode = OBJ_SECTORS;
              break;
            case OBJ_VERTEXES:
              map_info->edit_mode = OBJ_THINGS;
              break;
            case OBJ_LINEDEFS:
              map_info->edit_mode = OBJ_VERTEXES;
              break;
            case OBJ_SECTORS:
              map_info->edit_mode = OBJ_LINEDEFS;
              break;
            }
        }

      /* convert the selection if necessary */
      if (map_info->selected != NULL)
        {
          if (old_mode == OBJ_THINGS || map_info->edit_mode == OBJ_THINGS)
            ForgetSelection(&(map_info->selected));

          /* select all LineDefs bound to the selected Sectors */
          if (old_mode == OBJ_SECTORS && (map_info->edit_mode == OBJ_LINEDEFS
                                       || map_info->edit_mode == OBJ_VERTEXES))
            {
              Int16 l, sd;

              new_sel = NULL;
              for (l = map_info->level->num_linedefs - 1; l > 0; l--)
                {
                  sd = map_info->level->linedefs[l].sidedef1;
                  if (sd >= 0 && IsSelected(map_info->selected, map_info->level->sidedefs[sd].sector))
                    SelectObject(&new_sel, l);
                  else
                    {
                      sd = map_info->level->linedefs[l].sidedef2;
                      if (sd >= 0 && IsSelected(map_info->selected, map_info->level->sidedefs[sd].sector))
                        SelectObject(&new_sel, l);
                    }
                }
              /* replace the old selection by the new one */
              ForgetSelection(&(map_info->selected));
              map_info->selected = new_sel;
            }

          /* select all Vertices bound to the selected LineDefs */
          if ((old_mode == OBJ_LINEDEFS || old_mode == OBJ_SECTORS) && map_info->edit_mode == OBJ_VERTEXES)
            {
              LDPtr ldptr;

              new_sel = NULL;
              while (map_info->selected)
                {
                  ldptr = &(map_info->level->linedefs[map_info->selected->objnum]);
                  if (!IsSelected(new_sel, ldptr->start))
                    SelectObject(&new_sel, ldptr->start);
                  if (!IsSelected(new_sel, ldptr->end))
                    SelectObject(&new_sel, ldptr->end);
                  UnSelectObject(&(map_info->selected), map_info->selected->objnum);
                }
              /* replace the old selection by the new one (old one already empty) */
              map_info->selected = new_sel;
            }

          /* select all LineDefs that have both ends selected */
          if (old_mode == OBJ_VERTEXES && (map_info->edit_mode == OBJ_LINEDEFS || map_info->edit_mode == OBJ_SECTORS))
            {
              Int16 l;

              new_sel = NULL;
              for (l = map_info->level->num_linedefs - 1; l > 0; l--)
                if (IsSelected(map_info->selected, map_info->level->linedefs[l].start)
                 && IsSelected(map_info->selected, map_info->level->linedefs[l].end))
                  SelectObject(&new_sel, l);
              /* replace the old selection by the new one */
              ForgetSelection(&(map_info->selected));
              map_info->selected = new_sel;
            }

          /* select all Sectors that have their LineDefs selected */
          if ((old_mode == OBJ_LINEDEFS || old_mode == OBJ_VERTEXES) && map_info->edit_mode == OBJ_SECTORS)
            {
              Int16 l, sd;

              new_sel = NULL;
              /* select all Sectors... */
              for (l = map_info->level->num_sectors - 1; l > 0; l--)
                SelectObject(&new_sel, l);
              /* ... then unselect those that should not be in the list */
              for (l = map_info->level->num_linedefs; l > 0; l--)
                if (!IsSelected(map_info->selected, l))
                  {
                    sd = map_info->level->linedefs[l].sidedef1;
                    if (sd >= 0)
                      UnSelectObject(&new_sel, map_info->level->sidedefs[sd].sector);
                    sd = map_info->level->linedefs[l].sidedef2;
                    if (sd >= 0)
                      UnSelectObject(&new_sel, map_info->level->sidedefs[sd].sector);
                  }
              /* replace the old selection by the new one */
              ForgetSelection(&(map_info->selected));
              map_info->selected = new_sel;
            }
        }
    }
  OldObject = -1;
  if (map_info->selected != NULL)
    CurObject = map_info->selected->objnum;
  else if (GetMaxObjectNum(map_info->level, map_info->edit_mode) >= 0
           && Config.select0 == TRUE)
    CurObject = 0;
  else
    CurObject = -1;
}


/*
   Change the scale of the map (zoom centered on the pointer).
   If direct = TRUE, new_scale holds the new scale.  If direct = FALSE, the
   scale is incremented or decremented depending on the sign of new_scale.
*/

static void ChangeMapScale(MapInfoPtr map_info, Bool direct, float new_scale)
{
  map_info->orig_x += (Int16) ((PointerX - ScrCenterX) / map_info->map_scale);
  map_info->orig_y += (Int16) ((ScrCenterY - PointerY) / map_info->map_scale);
  if (direct == TRUE)
    map_info->map_scale = new_scale;
  else
    {
      if (new_scale > 0.0)
        {
          if (map_info->map_scale < 1.0)
            map_info->map_scale = 1.0 / ((1.0 / map_info->map_scale) - 1.0);
          else
            map_info->map_scale = map_info->map_scale * 2.0;
        }
      else
        {
          if (map_info->map_scale < 1.0)
            map_info->map_scale = 1.0 / ((1.0 / map_info->map_scale) + 1.0);
          else
            map_info->map_scale = map_info->map_scale / 2.0;
        }
    }
  map_info->orig_x -= (Int16) ((PointerX - ScrCenterX) / map_info->map_scale);
  map_info->orig_y -= (Int16) ((ScrCenterY - PointerY) / map_info->map_scale);
}


/*
   Move the map if the pointer is near the edge of the screen.
   Returns TRUE if the map has to be redrawn.
*/

static Bool ScrollMap(MapInfoPtr map_info)
{
  if (PointerY <= (UseMouse ? 2 : 20))
    {
      if (! UseMouse)
        PointerY += MoveSpeed;
      if (MAPY(ScrCenterY) < map_info->level->map_maxY)
        {
          map_info->orig_y += (Int16) (MoveSpeed * 2.0 / map_info->map_scale);
          return TRUE;
        }
    }
  if (PointerY >= ScrMaxY - (UseMouse ? 8 : 20))
    {
      if (! UseMouse)
        PointerY -= MoveSpeed;
      if (MAPY(ScrCenterY) > map_info->level->map_minY)
        {
          map_info->orig_y -= (Int16) (MoveSpeed * 2.0 / map_info->map_scale);
          return TRUE;
        }
    }
  if (PointerX <= (UseMouse ? 8 : 20))
    {
      if (! UseMouse)
        PointerX += MoveSpeed;
      if (MAPX(ScrCenterX) > map_info->level->map_minX)
        {
          map_info->orig_x -= (Int16) (MoveSpeed * 2.0 / map_info->map_scale);
          return TRUE;
        }
    }
  if (PointerX >= ScrMaxX - (UseMouse ? 8 : 20))
    {
      if (! UseMouse)
        PointerX -= MoveSpeed;
      if (MAPX(ScrCenterX) < map_info->level->map_maxX)
        {
          map_info->orig_x += (Int16) (MoveSpeed * 2.0 / map_info->map_scale);
          return TRUE;
        }
    }
  return FALSE;
}


/*--------------------------------------------------------------------------*/


/*
   Callback function for when the map editor window is closed.
*/

static Bool MapWindowClose(int window_num)
{
  MapInfoPtr mapw_info;

#ifdef NEW_CODE
  mapw_info = (MapInfoPtr)(win_info[window_num].info);
#else
  /*! kludge */
  mapw_info = xxx_info;
#endif
  if (mapw_info->level->made_changes
      && !Confirm(-1, -1,
                  "You have unsaved changes.",
                  "Do you really want to quit?"))
    return FALSE;
  LogMessage(": Finished editing %s...\n", "XXXX" /*! mapname */);
  if (mapw_info->selected != NULL)
    ForgetSelection(&(mapw_info->selected));
  if (mapw_info->level != NULL)
    ForgetLevelData(mapw_info->level);
  FreeMemory(mapw_info);
  return TRUE;
}


/*
   Callback function for redrawing the map.
*/

static void MapWindowRedraw(int window_num)
{
  MapInfoPtr mapw_info;

#ifdef NEW_CODE
  mapw_info = (MapInfoPtr)(win_info[window_num].info);
#else
  /*! kludge */
  mapw_info = xxx_info;
#endif
  Scale = mapw_info->map_scale;
  OrigX = mapw_info->orig_x;
  OrigY = mapw_info->orig_y;
#ifdef NEW_CODE
  ScrMaxX = win_info[window_num].width - 1;
  ScrMaxY = win_info[window_num].height - 1;
#endif

  /* redraw the map */
  DrawMap(mapw_info->level, mapw_info->edit_mode,
          mapw_info->grid_scale, mapw_info->grid_shown,
          mapw_info->thing_mask);
  /* re-highlight the objects */
  PointerModeRedraw(mapw_info);
  /* display the info box */
  if (PointerMode == PM_NORMAL)
    DisplayObjectInfo(mapw_info->level, mapw_info->edit_mode, CurObject);
  /* display the coordinates of the pointer */
  DisplayPointerCoords();
}



static void MapWindowMouseMoved(int window_num)
{
  MapInfoPtr mapw_info;
  Bool       redraw_map;

#ifdef NEW_CODE
  mapw_info = (MapInfoPtr)(win_info[window_num].info);
#else
  /*! kludge */
  mapw_info = xxx_info;
#endif

  OldObject = CurObject;
  switch (PointerMode)
    {
    case PM_NORMAL:
      redraw_map = FALSE;
      if ((GetAltKeys() & 0x03) == 0x00)  /* no shift keys */
        CurObject = GetCurObject(mapw_info->level, mapw_info->edit_mode,
                                 MAPX(PointerX - 4), MAPY(PointerY - 4),
                                 MAPX(PointerX + 4), MAPY(PointerY + 4));
      if (CurObject < 0)
        CurObject = OldObject;
      else if (CurObject != OldObject)
        {
          /* erase old yellow frame */
          if (OldObject >= 0)
            HighlightObject(mapw_info->level, mapw_info->edit_mode,
                            OldObject, YELLOW);
          /* beep */
          PlaySound(50, 10);

          /* draw new yellow frame */
          HighlightObject(mapw_info->level, mapw_info->edit_mode,
                          CurObject, YELLOW);
          /* update the info box */
#if 0
          if (IsKeyPressed()) / * speedup * /
            RedrawObj = TRUE;
          else
#endif
          DisplayObjectInfo(mapw_info->level, mapw_info->edit_mode, CurObject);
        }
      break;

    case PM_BOXSELECT:
      redraw_map = SelBoxModeMove(mapw_info);
      break;

    case PM_DRAG:
      redraw_map = DragModeMove(mapw_info);
      break;

    case PM_LINEDRAW:
      CurObject = GetCurObject(mapw_info->level, OBJ_VERTEXES,
                               MAPX(PointerX - 4), MAPY(PointerY - 4),
                               MAPX(PointerX + 4), MAPY(PointerY + 4));
      if (CurObject != OldObject)
        {
          if (OldObject >= 0)
            HighlightObject(mapw_info->level, OBJ_VERTEXES, OldObject, CYAN);
          PlaySound(70, 10);
          if (CurObject >= 0)
            HighlightObject(mapw_info->level, OBJ_VERTEXES, CurObject, CYAN);
        }
      redraw_map = LineDrawModeMove(mapw_info);
      break;

    case PM_BOXCREATE:
      redraw_map = FALSE;
      /*! ... */
      break;

    case PM_THINGROT:
      redraw_map = FALSE;
      /*! ... */
      break;

    default:
      ProgError("BUG: Invalid pointer mode (%d)", PointerMode);
      break;
    }

  /* scroll the map if the pointer is near the edge of the window and if the
     pointer is grabbed (special pointer mode) of if Scroll Lock is active */
  if ((PointerMode != PM_NORMAL || (GetAltKeys() & 0x10) != 0)
      && ScrollMap(mapw_info))
    redraw_map = TRUE;

  OldPointerX = PointerX;
  OldPointerY = PointerY;
#ifdef NEW_CODE
  if (redraw_map == TRUE)
    RedrawWindow(window_num);
#else
  if (redraw_map == TRUE)
    MapWindowRedraw(XXX_NO_WINDOWS);
#endif
  else
    DisplayPointerCoords();
}


/*
   Callback function for processing the actions (key or button pressed).
*/

static void MapWindowAction(int window_num, UInt16 key)
{
  MapInfoPtr mapw_info;
  SelPtr     tmp_sel;
  Bool       redraw_map;

#ifdef NEW_CODE
  mapw_info = (MapInfoPtr)(win_info[window_num].info);
#else
  /*! kludge */
  mapw_info = xxx_info;
#endif

  redraw_map = FALSE;
  /* convert mouse buttons to keys - could be cleaner... */
  switch (key)
    {
    case MOUSE_LEFTDOWN:
      if (PointerMode == PM_LINEDRAW)
        key = PCKEY_INS;
      else if (GetAltKeys() & 0x04) /* ctrl */
        key = PCKEY_CTRL_S;
      else if (GetAltKeys() & 0x03) /* shift */
        key = 'M';
      else
        key = 'm';
      break;
    case MOUSE_RIGHTDOWN:
      key = 'd';
      break;
    case MOUSE_MIDDLEDOWN:
      key = PCKEY_ENTER;
      break;
    case MOUSE_LEFTUP:
      if (PointerMode == PM_BOXSELECT)
        key = 'M';
      else if (PointerMode == PM_BOXCREATE)
        key = PCKEY_CTRL_S;
      break;
    case MOUSE_RIGHTUP:
      if (PointerMode == PM_DRAG)
        key = 'd';
      break;
    }
  switch (key)
    {
    case ' ':
      /*! should be replaced by dynamic pointer acceleration (MoveSpeedInc) */
      if (MoveSpeed == 20)
        MoveSpeed = 1;
      else
        MoveSpeed = 20;
      break;

    case 'q':
    case 'Q':
      if (PointerModeAbort(mapw_info))
        redraw_map = TRUE;
      if (CheckBeforeSaving(mapw_info->level))
        {
          if ((DoomVersion & 15) != 0 && mapw_info->level->made_changes)
            {
              char *outfile;

              outfile = GetNewWadFileName(GetLevelMapName(mapw_info->level),
                                          GetLevelFileName(mapw_info->level));
              if (outfile != NULL)
                {
                  /*! Temporary safeguard */
                  QuickSaveLevelData(mapw_info->level, "~DEU~TMP.WAD");
                  SaveLevelData(mapw_info->level, "????????.WAD", outfile);
#ifdef NEW_CODE
                  (void) CloseWindow(window_num);
#else
                  (void) MapWindowClose(XXX_NO_WINDOWS);
                  xxx_exit = TRUE;
#endif
                }
            }
          else
            {
#ifdef NEW_CODE
              (void) CloseWindow(window_num);
#else
              (void) MapWindowClose(XXX_NO_WINDOWS);
              xxx_exit = TRUE;
#endif
            }
        }
      redraw_map = TRUE;
      break;

    case PCKEY_ESC:
      if (PointerMode != PM_NORMAL)
        {
          if (PointerModeAbort(mapw_info))
            redraw_map = TRUE;
        }
      else
        {
          ForgetSelection(&(mapw_info->selected));
#ifdef NEW_CODE
          if (CloseWindow(window_num) == FALSE)
             redraw_map = TRUE;
#else
          if (MapWindowClose(XXX_NO_WINDOWS) == FALSE)
             redraw_map = TRUE;
          else
             xxx_exit = TRUE;
#endif
        }
      break;

    case PCKEY_CTRL_U:
      if (PointerMode == PM_NORMAL && UndoRedo(&(mapw_info->level)) == TRUE)
        redraw_map = TRUE;
      else
        Beep();
      break;

    case PCKEY_F1:
      DisplayHelp(mapw_info->edit_mode, mapw_info->grid_scale);
      redraw_map = TRUE;
      break;

    case PCKEY_F2:
      if (PointerModeAbort(mapw_info))
        redraw_map = TRUE;
      if ((DoomVersion & 15) != 0)
        {
          char *outfile;

          if (CheckBeforeSaving(mapw_info->level))
            {
              outfile = GetNewWadFileName(GetLevelMapName(mapw_info->level),
                                          GetLevelFileName(mapw_info->level));
              if (outfile != NULL)
                {
                  /*! Temporary safeguard */
                  QuickSaveLevelData(mapw_info->level, "~DEU~TMP.WAD");
                  SaveLevelData(mapw_info->level, "????????.WAD", outfile);
                }
            }
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case PCKEY_F3:
      if (PointerModeAbort(mapw_info))
        redraw_map = TRUE;
      if ((DoomVersion & 15) != 0)
        {
          if (CheckBeforeSaving(mapw_info->level))
            {
              char *outfile;
              char *newmapname;

              outfile = GetNewWadFileName(GetLevelMapName(mapw_info->level),
                                          GetLevelFileName(mapw_info->level));
              if (outfile != NULL)
                {
                  newmapname = SelectMapName(GetLevelMapName(mapw_info->level), TRUE);
                  if (newmapname != NULL
                      && strcmp(newmapname, GetLevelMapName(mapw_info->level)))
                    {
                      int     m;
                      MDirPtr newLevel, oldl, newl;

                      /* horrible but it works... */
                      newLevel = FindMasterDir(MasterDir, newmapname);
                      oldl = mapw_info->level->dir;
                      newl = newLevel;
                      for (m = 0; m < 11; m++)
                        {
                          newl->wadfile = oldl->wadfile;
                          if (m > 0)
                            newl->dir = oldl->dir;
                          /*
                             if (!strcmp(outfile, oldl->wadfile->filename))
                             {
                             oldl->wadfile = WadFileList;
                             oldl->dir = lost...
                             }
                          */
                          oldl = oldl->next;
                          newl = newl->next;
                        }
                      mapw_info->level->dir = newLevel;
                    }
                  /*! Temporary safeguard */
                  QuickSaveLevelData(mapw_info->level, "~DEU~TMP.WAD");
                  SaveLevelData(mapw_info->level, "????????.WAD", outfile);
                }
            }
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    /* case PCKEY_F4: */

    case PCKEY_F5:
      Preferences(-1, -1);
      redraw_map = TRUE;
      break;

    /* case PCKEY_F6: switch to next window (?) */

    case PCKEY_F7:
      /*! ask for the name of the file */
      if (Confirm(-1, -1, "Print the map to DEU-TEST.PS ?", NULL))
        PrintWad(mapw_info->level, "DEU-TEST.PS");
      redraw_map = TRUE;
      break;

    case PCKEY_F8:
      CheckPointUndo(mapw_info->level, "Misc. operation");
      if (PointerMode == PM_NORMAL)
        {
          tmp_sel = mapw_info->selected;
          if (tmp_sel == NULL && CurObject >= 0)
            SelectObject(&tmp_sel, CurObject);
          MiscOperations(mapw_info->level, -1, -1, mapw_info->edit_mode, &tmp_sel);
          if (mapw_info->selected == NULL)
            ForgetSelection(&tmp_sel);
          else
            mapw_info->selected = tmp_sel;
          CurObject = -1;
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case PCKEY_F9:
      CheckPointUndo(mapw_info->level, "Insert object");
      if (PointerMode == PM_NORMAL)
        {
          UInt16 savednum, i;

          savednum = mapw_info->level->num_linedefs;
          InsertStandardObject(mapw_info->level, -1, -1, MAPX(PointerX), MAPY(PointerY));
          if (mapw_info->level->num_linedefs > savednum)
            {
              ChangeEditMode(mapw_info, TRUE, OBJ_LINEDEFS);
              ForgetSelection(&(mapw_info->selected));
              for (i = savednum; i < mapw_info->level->num_linedefs; i++)
                SelectObject(&(mapw_info->selected), i);
              CurObject = mapw_info->level->num_linedefs - 1;
              OldObject = -1;
            }
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case PCKEY_F10:
      CheckPointUndo(mapw_info->level, "Check & repair");
      if (PointerMode == PM_NORMAL)
        {
          CheckLevel(mapw_info->level, -1, -1);
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case 'i':
    case 'I':
      Config.infoShown = !Config.infoShown;
      redraw_map = TRUE;
      break;

    case '+':
    case '=':
      if (mapw_info->map_scale < 4.0)
        {
          ChangeMapScale(mapw_info, FALSE, +1.0);
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case '-':
    case '_':
      if (mapw_info->map_scale > 0.05)
        {
          ChangeMapScale(mapw_info, FALSE, -1.0);
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case '0':
      ChangeMapScale(mapw_info, TRUE, 0.1);
      redraw_map = TRUE;
      break;

    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      ChangeMapScale(mapw_info, TRUE, 1.0 / (key - '0'));
      redraw_map = TRUE;
      break;

    case PCKEY_UP:
      if (MoveSpeed <= PointerY)
        {
          if (UseMouse)
            SetMouseCoords(PointerX, PointerY - MoveSpeed);
          else
            PointerY -= MoveSpeed;
        }
      else
        Beep();
      break;

    case PCKEY_DOWN:
      if ((PointerY + MoveSpeed) <= ScrMaxY)
        {
          if (UseMouse)
            SetMouseCoords(PointerX, PointerY + MoveSpeed);
          else
            PointerY += MoveSpeed;
        }
      else
        Beep();
      break;

    case PCKEY_LEFT:
      if (MoveSpeed <= PointerX)
        {
          if (UseMouse)
            SetMouseCoords(PointerX - MoveSpeed, PointerY);
          else
            PointerX -= MoveSpeed;
        }
      else
        Beep();
      break;

    case PCKEY_RIGHT:
      if ((PointerX + MoveSpeed) <= ScrMaxX)
        {
          if (UseMouse)
            SetMouseCoords(PointerX + MoveSpeed, PointerY);
          else
            PointerX += MoveSpeed;
        }
      else
        Beep();
      break;


    case PCKEY_PGUP:
      if (MAPY(ScrCenterY) < mapw_info->level->map_maxY)
        {
          mapw_info->orig_y += (Int16) (ScrCenterY / mapw_info->map_scale);
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case PCKEY_PGDN:
      if (MAPY(ScrCenterY) > mapw_info->level->map_minY)
        {
          mapw_info->orig_y -= (Int16) (ScrCenterY / mapw_info->map_scale);
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case PCKEY_HOME:
      if (MAPX(ScrCenterX) > mapw_info->level->map_minX)
        {
          mapw_info->orig_x -= (Int16) (ScrCenterX / mapw_info->map_scale);
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case PCKEY_END:
      if (MAPX(ScrCenterX) < mapw_info->level->map_maxX)
        {
          mapw_info->orig_x += (Int16) (ScrCenterX / mapw_info->map_scale);
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case PCKEY_TAB:
      ChangeEditMode(mapw_info, FALSE, +1);
      redraw_map = TRUE;
      break;

    case PCKEY_SHIFT_TAB:
      ChangeEditMode(mapw_info, FALSE, -1);
      redraw_map = TRUE;
      break;

    case 't':
    case 'T':
      ChangeEditMode(mapw_info, TRUE, OBJ_THINGS);
      redraw_map = TRUE;
      break;

    case 'v':
    case 'V':
      ChangeEditMode(mapw_info, TRUE, OBJ_VERTEXES);
      redraw_map = TRUE;
      break;

    case 'l':
    case 'L':
      ChangeEditMode(mapw_info, TRUE, OBJ_LINEDEFS);
      redraw_map = TRUE;
      break;

    case 's':
    case 'S':
      ChangeEditMode(mapw_info, TRUE, OBJ_SECTORS);
      redraw_map = TRUE;
      break;

    case 'g':
      if (mapw_info->grid_scale == 0)
        mapw_info->grid_scale = 256;
      else if (mapw_info->grid_scale > 8)
        mapw_info->grid_scale /= 2;
      else
        mapw_info->grid_scale = 0;
      redraw_map = TRUE;
      break;

    case 'G':
      if (mapw_info->grid_scale == 0)
        mapw_info->grid_scale = 8;
      else if (mapw_info->grid_scale < 256)
        mapw_info->grid_scale *= 2;
      else
        mapw_info->grid_scale = 0;
      redraw_map = TRUE;
      break;

    case PCKEY_ALT_0:
      mapw_info->grid_scale = 0;
      redraw_map = TRUE;
      break;

    case PCKEY_ALT_3:
      mapw_info->grid_scale = 8;
      redraw_map = TRUE;
      break;

    case PCKEY_ALT_4:
      mapw_info->grid_scale = 16;
      redraw_map = TRUE;
      break;

    case PCKEY_ALT_5:
      mapw_info->grid_scale = 32;
      redraw_map = TRUE;
      break;

    case PCKEY_ALT_6:
      mapw_info->grid_scale = 64;
      redraw_map = TRUE;
      break;

    case PCKEY_ALT_7:
      mapw_info->grid_scale = 128;
      redraw_map = TRUE;
      break;

    case PCKEY_ALT_8:
      mapw_info->grid_scale = 256;
      redraw_map = TRUE;
      break;

    case 'h':
    case 'H':
      mapw_info->grid_shown = !(mapw_info->grid_shown);
      redraw_map = TRUE;
      break;

    case 'r':
    case 'R':
      mapw_info->show_rulers = !(mapw_info->show_rulers);
      break;

    case 'n':
    case 'N':
    case '>':
      if (PointerMode == PM_NORMAL)
        {
          tmp_sel = mapw_info->selected;
          if (key == 'N' && tmp_sel != NULL) /* next in selection */
            {
              while (tmp_sel != NULL && tmp_sel->objnum != CurObject)
                tmp_sel = tmp_sel->next;
              if (tmp_sel->next != NULL)
                CurObject = tmp_sel->next->objnum;
              else
                CurObject = mapw_info->selected->objnum;
            }
          else if (CurObject < GetMaxObjectNum(mapw_info->level, mapw_info->edit_mode))
            (CurObject)++;
          else if (GetMaxObjectNum(mapw_info->level, mapw_info->edit_mode) >= 0)
            CurObject = 0;
          else
            CurObject = -1;
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case 'p':
    case 'P':
    case '<':
      if (PointerMode == PM_NORMAL)
        {
          tmp_sel = mapw_info->selected;
          if (key == 'P' && tmp_sel != NULL) /* next in selection */
            {
              while (tmp_sel->next != NULL && tmp_sel->next->objnum != CurObject)
                tmp_sel = tmp_sel->next;
              CurObject = tmp_sel->objnum;
            }
          else if (CurObject > 0)
            (CurObject)--;
          else
            CurObject = GetMaxObjectNum(mapw_info->level, mapw_info->edit_mode);
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case 'j':
    case 'J':
    case '#':
      if (PointerMode == PM_NORMAL)
        {
          char prompt[80];

          sprintf(prompt, "Enter a %s number between 0 and %d:",
                  GetObjectTypeName(mapw_info->edit_mode),
                  GetMaxObjectNum(mapw_info->level, mapw_info->edit_mode));
          OldObject = InputIntegerValue(-1, -1, prompt,
                                        0,
                                        GetMaxObjectNum(mapw_info->level,
                                                        mapw_info->edit_mode),
                                        CurObject);
          if (OldObject >= 0)
            {
              CurObject = OldObject;
              GoToObject(mapw_info->level, mapw_info->edit_mode, CurObject);
            }
          else
            OldObject = CurObject;
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case 'd':
    case 'D':
      if (PointerMode == PM_NORMAL)
        {
          CheckPointUndo(mapw_info->level, "Drag objects");
          DragModeStart(mapw_info);
        }
      else if (PointerMode == PM_DRAG)
        {
          if (DragModeEnd(mapw_info))
            redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case 'm':
      if (PointerMode == PM_NORMAL)
        {
          if (CurObject >= 0)
            {
              /* mark or unmark one object */
              if (IsSelected(mapw_info->selected, CurObject))
                UnSelectObject(&(mapw_info->selected), CurObject);
              else
                SelectObject(&(mapw_info->selected), CurObject);
              HighlightObject(mapw_info->level, mapw_info->edit_mode,
                              CurObject, GREEN);
              if (mapw_info->selected)
                PlaySound(440, 10);
            }
          else
            Beep();
        }
      else if (PointerMode == PM_BOXSELECT)
        {
          if (SelBoxModeEnd(mapw_info))
            redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case 'M':
      if (PointerMode == PM_NORMAL)
        {
      CheckPointUndo(mapw_info->level, "Check & repair");
          SelBoxModeStart(mapw_info);
        }
      else if (PointerMode == PM_BOXSELECT)
        {
          if (SelBoxModeEnd(mapw_info))
            redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case 'c':
    case 'C':
      (void) PointerModeAbort(mapw_info);
      ForgetSelection(&(mapw_info->selected));
      redraw_map = TRUE;
      break;

    case 'o':
    case 'O':
      Beep();
      Notify(-1, -1, "Use 'Ctrl-D' instead of 'O' to duplicate objects", NULL);
      redraw_map = TRUE;
      break;

    case PCKEY_CTRL_D:
      if (PointerMode == PM_NORMAL && CurObject >= 0)
        {
          CheckPointUndo(mapw_info->level, "Duplicate objects");
          /* copy the object(s) */
          if (mapw_info->selected == NULL)
            SelectObject(&(mapw_info->selected), CurObject);
          DuplicateObjects(mapw_info->level, mapw_info->edit_mode, mapw_info->selected);
          DragModeStart(mapw_info);
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case PCKEY_ENTER:
      if (PointerMode == PM_NORMAL && CurObject >= 0)
        {
          CheckPointUndo(mapw_info->level, "Edit objects");
          tmp_sel = mapw_info->selected;
          if (tmp_sel == NULL)
            SelectObject(&tmp_sel, CurObject);
          EditObjectsInfo(mapw_info->level, 0, 30, mapw_info->edit_mode, tmp_sel);
          if (mapw_info->selected == NULL)
            ForgetSelection(&tmp_sel);
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case PCKEY_DEL:
      if (PointerMode == PM_NORMAL && CurObject >= 0)
        {
          if (mapw_info->edit_mode == OBJ_THINGS
              || Config.expert
              || Confirm(-1, -1,
                         (mapw_info->selected ?
                          "Do you really want to delete these objects?" :
                          "Do you really want to delete this object?"),
                         (mapw_info->selected ?
                          "This will also delete the objects bound to them." :
                          "This will also delete the objects bound to it.")))
            {
              CheckPointUndo(mapw_info->level, "Delete objects");
              if (mapw_info->selected)
                DeleteObjects(mapw_info->level, mapw_info->edit_mode, &(mapw_info->selected));
              else
                DeleteObject(mapw_info->level, mapw_info->edit_mode, CurObject);
              CurObject = -1;
            }
          redraw_map = TRUE;
        }
      else
        Beep();
      break;

    case PCKEY_INS:
      if (PointerMode == PM_NORMAL)
        {
          CheckPointUndo(mapw_info->level, "Insert objects");
          if (mapw_info->edit_mode == OBJ_VERTEXES
              && mapw_info->selected != NULL
              && mapw_info->selected->next != NULL)
            {
              CreateLineDefs(mapw_info->level, &(mapw_info->selected));
              ChangeEditMode(mapw_info, FALSE, +1);
            }
          else if (mapw_info->edit_mode == OBJ_LINEDEFS
                   && mapw_info->selected != NULL
                   && mapw_info->selected->next != NULL)
            {
              CreateSector(mapw_info->level, &(mapw_info->selected));
              ChangeEditMode(mapw_info, FALSE, +1);
            }
          else if (mapw_info->edit_mode == OBJ_LINEDEFS)
            {
              CheckPointUndo(mapw_info->level, "Draw lines");
              LineDrawModeStart(mapw_info);
            }
          else
            {
              ForgetSelection(&(mapw_info->selected));
              if (mapw_info->grid_scale > 0)
                InsertObject(mapw_info->level, mapw_info->edit_mode, CurObject,
                             (Int16) ((int)(MAPX(PointerX) + mapw_info->grid_scale / 2))
                               & ((int)(~(mapw_info->grid_scale - 1))),
                             (Int16) ((int)(MAPY(PointerY) + mapw_info->grid_scale / 2))
                               & ((int)(~(mapw_info->grid_scale - 1))));
              else
                InsertObject(mapw_info->level, mapw_info->edit_mode, CurObject,
                             MAPX(PointerX),
                             MAPY(PointerY));
              CurObject = GetMaxObjectNum(mapw_info->level, mapw_info->edit_mode);
              if (mapw_info->edit_mode == OBJ_VERTEXES)
                {
                  SelectObject(&(mapw_info->selected), CurObject);
                  if (AutoMergeVertices(mapw_info->level, &(mapw_info->selected)))
                    redraw_map = TRUE;
                  ForgetSelection(&(mapw_info->selected));
                }
            }
          redraw_map = TRUE;
        }
      else if (PointerMode == PM_LINEDRAW)
        {
          if (CurObject < 0)
            LineDrawAddVertex(mapw_info);
          else
            {
              LineDrawAddVertex(mapw_info);
              if (LineDrawModeEnd(mapw_info))
                redraw_map = TRUE;
            }
        }
      else
        Beep();
      break;

    case PCKEY_CTRL_INS:
      if (PointerMode == PM_NORMAL && CurObject >= 0)
        {
          tmp_sel = mapw_info->selected;
          if (tmp_sel == NULL)
            SelectObject(&tmp_sel, CurObject);
          ForgetLevelData(level_clipboard);
          level_clipboard = LevelCopy(mapw_info->level, mapw_info->edit_mode,
                                      tmp_sel);
          if (mapw_info->selected == NULL)
            ForgetSelection(&tmp_sel);
        }
      else
        Beep();
      break;

    case PCKEY_SHIFT_INS:
      if (PointerMode == PM_NORMAL && level_clipboard != NULL)
        {
          LevelPtr level_tmp;

          CheckPointUndo(mapw_info->level, "Paste objects");
          /*! temporary hack: first, copy the clipboard in a temporary level;
              then adjust the coordinates of this level so that the objects
              are created under the pointer; finally, paste the objects and
              forget the temporary level.
              There should be a cleaner way to do that!  The drag mode should
              be activated automatically on this temporary level (maybe a
              special drag mode which uses LevelMove).  Or maybe select the
              objects that have been copied so that it is easy to drag them.
          */
          level_tmp = LevelDuplicate(level_clipboard);
          if (mapw_info->grid_scale > 0)
            LevelMove(level_tmp,
                      (Int16) ((int)(MAPX(PointerX)
                                     - level_tmp->map_minX
                                     + mapw_info->grid_scale / 2))
                               & ((int)(~(mapw_info->grid_scale - 1))),
                      (Int16) ((int)(MAPY(PointerY)
                                     - level_tmp->map_minY
                                     + mapw_info->grid_scale / 2))
                               & ((int)(~(mapw_info->grid_scale - 1))));
          else
            LevelMove(level_tmp,
                      MAPX(PointerX) - level_tmp->map_minX,
                      MAPY(PointerY) - level_tmp->map_minY);
          LevelPaste(mapw_info->level, level_tmp);
          ForgetLevelData(level_tmp);
        }
      else
        Beep();
      break;

    case PCKEY_SHIFT_DEL:
      if (PointerMode == PM_NORMAL && CurObject >= 0)
        {
          CheckPointUndo(mapw_info->level, "Cut objects");
          if (mapw_info->selected == NULL)
            SelectObject(&(mapw_info->selected), CurObject);
          ForgetLevelData(level_clipboard);
          level_clipboard = LevelCut(mapw_info->level, mapw_info->edit_mode,
                                     &(mapw_info->selected));
        }
      else
        Beep();
      break;

    case MOUSE_LEFTDOWN:
    case MOUSE_RIGHTDOWN:
    case MOUSE_MIDDLEDOWN:
    case MOUSE_LEFTUP:
    case MOUSE_RIGHTUP:
    case MOUSE_MIDDLEUP:
       /* no beep */
       break;

    default:
      /* user likes music */
      Beep();
    }
#ifdef NEW_CODE
  if (redraw_map == TRUE)
    RedrawWindow(window_num);
#else
  if (redraw_map == TRUE && xxx_exit == FALSE)
    MapWindowRedraw(XXX_NO_WINDOWS);
#endif
  else
    DisplayPointerCoords();
}



/*
   Open a new window for the map editor and save some useful informations.
*/

static Bool MapWindowOpen(char *mapname, Bool newlevel)
{
  int        new_window;
  MapInfoPtr new_info;

  new_info = (struct MapEditorInfo *)GetMemory(sizeof(struct MapEditorInfo));

  if (newlevel)
    new_info->level = CreateNewLevel(mapname);
  else
    new_info->level = LoadLevelData(mapname, "????????.WAD"); /*! fix file name */
  if (new_info->level == NULL)
    ProgError("BUG: level data not found.");
  LogMessage(": Editing map %s from %s...\n", mapname, "????????.WAD");
  new_info->level->made_changes = FALSE;
  new_info->level->made_map_changes = FALSE;

  new_info->edit_mode = OBJ_THINGS;
  new_info->selected = NULL;
  PointerMode = PM_NORMAL;
  CurObject = -1;
  OldObject = -1;

  if (Config.initialScale < 1)
    Config.initialScale = 1;
  else if (Config.initialScale > 20)
    Config.initialScale = 20;
  new_info->map_scale = (float) (1.0 / Config.initialScale);

  new_info->grid_scale = 0;
  new_info->grid_shown = TRUE;
  new_info->show_rulers = FALSE;
  new_info->thing_mask = 0x17; /* (D12 D3 D45 !Net) */
  new_info->orig_x = (new_info->level->map_minX
                      + new_info->level->map_maxX) / 2;
  new_info->orig_y = (new_info->level->map_minY
                      + new_info->level->map_maxY) / 2;

#ifdef NEW_CODE
  new_window = CreateNewWindow(xxx_info, mapname);
  if (new_window < 0)
    {
      LogMessage(": Editing aborted (cannot open a new window).\n");
      ForgetLevelData(new_info->level);
      FreeMemory(new_info);
      return FALSE;
    }
  RegisterRedrawCB(new_window, MapWindowRedraw);
  RegisterActionCB(new_window, MapWindowAction);
  RegisterMousemCB(new_window, MapWindowMouseMoved);
  RegisterCloseCB( new_window, MapWindowClose);
  RaiseWindow(new_window);
#else
  /*! temporary kludge: use global variables */
  xxx_info = new_info;
  xxx_exit = FALSE;
  MapWindowRedraw(XXX_NO_WINDOWS);
#endif
  return TRUE;
}


/*--------------------------------------------------------------------------*/


/*
   The *OLD* editor main loop (should be changed!).
*/

static void OLD_EditorLoop(void)
{
  Int16      key;
  UInt16     buttons, oldbuttons;
  MapInfoPtr mapw_info;
  Bool       redraw_map;

  mapw_info = xxx_info;
  PointerX = ScrCenterX;
  PointerY = ScrCenterY;
  if (UseMouse)
    {
      ResetMouseLimits();
      SetMouseCoords(ScrCenterX, ScrCenterY);
      /* ShowMousePointer(); */
      oldbuttons = 0;
    }
  else
    Config.fakeCursor = TRUE;

  redraw_map = FALSE;
  for (xxx_exit = FALSE; xxx_exit == FALSE;)
    {
      key = 0;

      /* get mouse position and button status */
      if (UseMouse)
        {
          if (Config.fakeCursor || mapw_info->show_rulers)
            {
              HideMousePointer();
              DrawPointer(mapw_info->show_rulers);
              ShowMousePointer();
            }
          GetMouseCoords(&PointerX, &PointerY, &buttons);
          if (Config.fakeCursor || mapw_info->show_rulers)
            {
              HideMousePointer();
              DrawPointer(mapw_info->show_rulers);
              ShowMousePointer();
            }
          if (PointerX != OldPointerX || PointerY != OldPointerY)
            {
              /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
              MapWindowMouseMoved(XXX_NO_WINDOWS);
            }
          if (buttons == 1 && PointerY < 17)
            {
              /* kluge for the menu bar */
              if (PointerX < 12)
                Beep();
              else if (PointerX < 60)
                key = PCKEY_ALT_F;
              else if (PointerX < 108)
                key = PCKEY_ALT_E;
              else if (PointerX < 172)
                key = PCKEY_ALT_S;
              else if (PointerX < 228)
                key = PCKEY_ALT_M;
              else if (PointerX < 300)
                key = PCKEY_ALT_O;
              else if (PointerX < 356)
                key = PCKEY_ALT_C;
              else if (PointerX < 446)
                key = PCKEY_ALT_T;
              else if (PointerX < ScrMaxX - 43)
                Beep();
              else
                key = PCKEY_ALT_H;
#ifdef DEBUG_MENUPOS
              HideMousePointer();
              SetColor(LIGHTMAGENTA);
              DrawScreenLine(12, 0, 12, 16);
              DrawScreenLine(60, 0, 60, 16);
              DrawScreenLine(108, 0, 108, 16);
              DrawScreenLine(172, 0, 172, 16);
              DrawScreenLine(228, 0, 228, 16);
              DrawScreenLine(300, 0, 300, 16);
              DrawScreenLine(356, 0, 356, 16);
              DrawScreenLine(446, 0, 446, 16);
              DrawScreenLine(ScrMaxX - 43, 0, ScrMaxX - 43, 16);
              ShowMousePointer();
#endif
            }
          else
            {
              if (buttons != oldbuttons)
                {
                  if (buttons == 1)
                    key = (Config.swapButtons ? MOUSE_RIGHTDOWN : MOUSE_LEFTDOWN);
                  else if (buttons == 2)
                    key = (Config.swapButtons ? MOUSE_LEFTDOWN : MOUSE_RIGHTDOWN);
                  else if (buttons == 4)
                    key = MOUSE_MIDDLEDOWN;
                  else if (oldbuttons == 1)
                    key = (Config.swapButtons ? MOUSE_RIGHTUP : MOUSE_LEFTUP);
                  else if (oldbuttons == 2)
                    key = (Config.swapButtons ? MOUSE_LEFTUP : MOUSE_RIGHTUP);
                  else if (oldbuttons == 4)
                    key = MOUSE_MIDDLEUP;
                  /*!
                  LogMessage("buttons = 0x%x, oldbuttons = 0x%x, key = 0x%4X\n",
                             buttons, oldbuttons, key);
                  */
                }
            }
          oldbuttons = buttons;
        }

      /* get user input */
#if defined(DEU_GFX_X11) || defined(DEU_GFX_SGI)
      /*! This will have to be changed: each event should call the
          appropriate callback function for the window in which it
          happens.  See i_window.c. */
      /* key != 0 if it has been modified by the mouse handler */
      if (key == 0)
        key = WaitForKey();
      if (key != 0)
        {
          /* hack: handle expose events */
          if (key == MAGIC_REDRAW_KEY)
            {
              RedrawMap = TRUE;
              continue;
            }
#else
      /* key != 0 if it has been modifier by the mouse handler */
      if (IsKeyPressed() || key != 0)
        {
          if (key == 0)
            key = WaitForKey();
#endif

          /*!
              These horrible menus should be replaced by something cleaner!
          */
          if (PointerMode == PM_NORMAL)
            switch (key)
            {
            case PCKEY_ALT_F:
              key = PullDownMenu(18, 19,
                                 "Save         F2", PCKEY_F2,    (Int16) 'S', 1,
                                 "Save As ExMx F3", PCKEY_F3,    (Int16) 'A', 6,
                                 "Print        F6", PCKEY_F6,    (Int16) 'P', 1,
                                 "Quit          Q", (Int16) 'Q', (Int16) 'Q', 1,
                                 NULL);
              redraw_map = TRUE;
              break;

            case PCKEY_ALT_E:
              key = PullDownMenu(66, 19,
                                 "Undo/Redo           U", PCKEY_CTRL_U, (Int16) 'U', 1,
                                 "Copy object(s)      O", (Int16) 'O', (Int16) 'C', 1,
                                 "Add object        Ins", PCKEY_INS, (Int16) 'A', 1,
                                 "Delete object(s)  Del", PCKEY_DEL, (Int16) 'D', 1,
                                 "Preferences        F5", PCKEY_F5,  (Int16) 'P', 1,
                                 NULL);
              redraw_map = TRUE;
              break;

            case PCKEY_ALT_S:
              key = PullDownMenu(114, 19,
                                 "Find/Change       F4", -1,        (Int16) 'F', -1,
                                 "Repeat last find    ", -1,        (Int16) 'R', -1,
                                 "Next object        N", (Int16) 'N', (Int16) 'N', 1,
                                 "Prev object        P", (Int16) 'P', (Int16) 'P', 1,
                                 "Jump to object...  J", (Int16) 'J', (Int16) 'J', 1,
                                 NULL);
              redraw_map = TRUE;
              break;

            case PCKEY_ALT_M:
              key = PullDownMenu(178, 19,
                                 ((mapw_info->edit_mode == OBJ_THINGS) ?
                                  "û Things              T" :
                                  "  Things              T"), (Int16) 'T', (Int16) 'T', 3,
                                 ((mapw_info->edit_mode == OBJ_LINEDEFS) ?
                                  "û Linedefs+Sidedefs   L" :
                                  "  Linedefs+Sidedefs   L"), (Int16) 'L', (Int16) 'L', 3,
                                 ((mapw_info->edit_mode == OBJ_VERTEXES) ?
                                  "û Vertexes            V" :
                                  "  Vertexes            V"), (Int16) 'V', (Int16) 'V', 3,
                                 ((mapw_info->edit_mode == OBJ_SECTORS) ?
                                  "û Sectors             S" :
                                  "  Sectors             S"), (Int16) 'S', (Int16) 'S', 3,
                                 "  Next mode         Tab",  PCKEY_TAB,    (Int16) 'N', 3,
                                 "  Last mode   Shift+Tab",  PCKEY_SHIFT_TAB, (Int16) 'L', 3,
                                 "  3D Preview          3",  (Int16) '3', (Int16) '3', -1,
                                 NULL);
              redraw_map = TRUE;
              break;

            case PCKEY_ALT_O:
              key = 0;
              /* don't want to create the object behind the menu bar... */
              if (PointerY < 20)
                {
                  PointerX = ScrCenterX;
                  PointerY = ScrCenterY;
                }
              /* yuck! */
              {
                UInt16 savednum, i;

                /* code duplicated from 'F9' - I hate to do that */
                savednum = mapw_info->level->num_linedefs;
                InsertStandardObject(mapw_info->level, 234, 19, MAPX(PointerX), MAPY(PointerY));
                if (mapw_info->level->num_linedefs > savednum)
                  {
                    ChangeEditMode(mapw_info, TRUE, OBJ_LINEDEFS);
                    ForgetSelection(&(mapw_info->selected));
                    for (i = savednum; i < mapw_info->level->num_linedefs; i++)
                      SelectObject(&(mapw_info->selected), i);
                    CurObject = mapw_info->level->num_linedefs - 1;
                    OldObject = -1;
                  }
              }
              redraw_map = TRUE;
              break;

            case PCKEY_ALT_C:
              key = 0;
              CheckLevel(mapw_info->level, 306, 19);
              redraw_map = TRUE;
              break;

            case PCKEY_ALT_T:
              key = 0;
              /* yuck! */
              {
                SelPtr tmp_sel;

                /* code duplicated from 'F8' - I hate to do that */
                tmp_sel = mapw_info->selected;
                if (tmp_sel == NULL && CurObject >= 0)
                  SelectObject(&tmp_sel, CurObject);
                MiscOperations(mapw_info->level, 362, 19,
                               mapw_info->edit_mode, &tmp_sel);
                if (mapw_info->selected == NULL)
                  ForgetSelection(&tmp_sel);
                else
                  mapw_info->selected = tmp_sel;
                CurObject = -1;
              }
              redraw_map = TRUE;
              break;

            case PCKEY_ALT_H:
              key = PullDownMenu(ScrMaxX, 19,
                                 "  Keyboard & mouse  F1",  0x3B00,    (Int16) 'K', 3,
                                 (Config.infoShown ?
                                  "û Info bar           I" :
                                  "  Info bar           I"), (Int16) 'I', (Int16) 'I', 3,
                                 "  About DEU...        ",  -1,        (Int16) 'A', -1,
                                 NULL);
              redraw_map = TRUE;
              break;
            }

          /* User wants to do the impossible. */
          if (key == -1)
            {
              key = 0;
              NotImplemented();
              redraw_map = TRUE;
            }

          /* erase the (keyboard) pointer */
          if (Config.fakeCursor || mapw_info->show_rulers)
            {
              if (UseMouse)
                HideMousePointer();
              DrawPointer(mapw_info->show_rulers);
              if (UseMouse)
                ShowMousePointer();
            }

          if (key != 0)
            /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
            MapWindowAction(XXX_NO_WINDOWS, key);

          /* redraw the (keyboard) pointer */
          if (Config.fakeCursor || mapw_info->show_rulers)
            {
              if (UseMouse)
                HideMousePointer();
              DrawPointer(mapw_info->show_rulers);
              if (UseMouse)
                ShowMousePointer();
            }
        }
      if (redraw_map == TRUE)
        {
          MapWindowRedraw(XXX_NO_WINDOWS);
          redraw_map = FALSE;
        }
    }
}



/*
   The driving program: switch to graphics mode and start the map editor.
*/

void OLD_EditLevel(char *mapname, Bool newlevel)
{
  char     *swgame;

  ReadWTextureNames();
  ReadFTextureNames();
  InitGfx();
  mapname = SelectMapName(mapname, newlevel);
  if (mapname != NULL)
    {
      ClearScreen();
      if (MapWindowOpen(mapname, newlevel) == FALSE)
        {
          Notify(-1, -1, "Cannot open new window", NULL);
          return;
        }
      OLD_EditorLoop();

      TermGfx();
      if (DoomVersion == 0)
        swgame = "DOOM";
      else if (DoomVersion == 16)
        swgame = "HERETIC";
      else if (DoomVersion == 32)
        swgame = "STRIFE";
      else if (DoomVersion == 48)
        swgame = "ZARCON7";
      if ((DoomVersion & 15) == 0)
        printf("Please register %s if you want to be able to save your changes.\n", swgame);
    }
  else
    TermGfx();
  ForgetWTextureNames();
  ForgetFTextureNames();
}

/* end of file */
