//
// The Fusion Library Interface for DOS
// Version 1.02
// Copyright (C) 1990, 1991
// Software Dimensions
//
// Dialog Development System
//

#include "fliwin.h"
#include "colors.h"
#include "dds.h"

#include <stdio.h>
#include <alloc.h>
#include <mem.h>
#include <string.h>

//-------------------------------------------------------------------------
//
// Place an object on the dialog
//
//-------------------------------------------------------------------------

void DialogWindow::PlaceObject(int Object)
{
  RemoveTheMenus();

  Pieces=(PieceHandler **)realloc(Pieces,++NumberPieces*sizeof(char *));

  switch (Object)
  {
    case PieceHandler::Box:
      Pieces[NumberPieces-1]=new Box(&Blaze,CursorX,CursorY,2,2,CurrentColor);
      break;

    case PieceHandler::FilledBox:
      Pieces[NumberPieces-1]=new FilledBox(&Blaze,CursorX,CursorY,2,2,CurrentColor);
      break;

    case PieceHandler::HorizontalLine:
      Pieces[NumberPieces-1]=new HorizontalLine(&Blaze,CursorX,CursorY,1,1,CurrentColor);
      break;

    case PieceHandler::VerticalLine:
      Pieces[NumberPieces-1]=new VerticalLine(&Blaze,CursorX,CursorY,1,1,CurrentColor);
      break;

    case PieceHandler::Shadow:
      Pieces[NumberPieces-1]=new Shadow(&Blaze,CursorX,CursorY,1,1);
      break;

    case PieceHandler::EraseArea:
      Pieces[NumberPieces-1]=new EraseArea(&Blaze,CursorX,CursorY,1,1,CurrentColor);
      break;

    case PieceHandler::ColorizeArea:
      Pieces[NumberPieces-1]=new ColorizeArea(&Blaze,CursorX,CursorY,1,1,CurrentColor);
      break;
  }

  MouseHide();

  PieceHandler &Piece=*Pieces[NumberPieces-1];

  Piece.DrawFigure();
  Blaze.HelpLine(0,"Use the keyboard or mouse to size the object (Esc aborts)");
  MouseShow();

  // Size the object

  Event EventHandler;

  MousePosition(X+Piece.X+Piece.Width,Y+Piece.Y+Piece.Height);
  MouseLocate();

  int MouseX=MouseHorizontal;
  int MouseY=MouseVertical;

  for (;;)
  {
    switch (EventHandler.GetEvent())
    {
      case kbUp:
        Piece.Size(0,-1);
        VirtualizedInterior();
        break;

      case kbDown:
        Piece.Size(0,1);
        if (Piece.Y+Piece.Height>Blaze.WhatWinHeight()-1)
          Piece.Size(0,-((Piece.Y+Piece.Height)-Blaze.WhatWinHeight()));
        VirtualizedInterior();
        break;

      case kbLeft:
        Piece.Size(-1,0);
        VirtualizedInterior();
        break;

      case kbRight:
        Piece.Size(1,0);
        if (Piece.X+Piece.Width>Blaze.WhatWinWidth()-1)
          Piece.Size(-((Piece.X+Piece.Width)-Blaze.WhatWinWidth()),0);
        VirtualizedInterior();
        break;

      case MousedEvent:
        if (MouseEvent&MouseMoved)
        {
          int NewX=MouseHorizontal-MouseX;
          int NewY=MouseVertical-MouseY;
          MouseX=MouseHorizontal;
          MouseY=MouseVertical;
          Piece.Size(NewX,NewY);

          if (Piece.X+Piece.Width>Blaze.WhatWinWidth()-1)
            Piece.Size(-((Piece.X+Piece.Width)-Blaze.WhatWinWidth()),0);
          if (Piece.Y+Piece.Height>Blaze.WhatWinHeight()-1)
            Piece.Size(0,-((Piece.Y+Piece.Height)-Blaze.WhatWinHeight()));

          if (MouseX!=X+Piece.X+Piece.Width || MouseY!=Y+Piece.Y+Piece.Height)
          {
            MousePosition(X+Piece.X+Piece.Width,Y+Piece.Y+Piece.Height);
            MouseLocate();
            MouseX=MouseHorizontal;
            MouseY=MouseVertical;
          }

          VirtualizedInterior();
        }
        if (MouseEvent&MouseLeftButtonRelease)
          return;
        break;

      case kbCr:
        return;

      case kbEsc:
        delete Pieces[NumberPieces-1];
        NumberPieces--;
        VirtualizedInterior();
        return;
    }
  }
}

//-------------------------------------------------------------------------
//
// Move an object around on the dialog
//
//-------------------------------------------------------------------------

int DialogWindow::MoveObject(int Moused,int PlaceObject)
{
  if (NumberPieces)
  {
    // Give elements priority for movement

    for (int i=NumberPieces-1;i>=0;i--)
    {
      PieceHandler &Piece=*Pieces[i];

      int PromptWidth=0;

      if (Piece.Prompter && *Piece.Prompter)
      {
        PromptWidth=strlen(Piece.Prompter)-(strchr(Piece.Prompter,'~')?1:0);
      }

      if (CursorX>=Piece.X &&
        CursorY>=Piece.Y &&
        CursorX<Piece.X+Piece.Width &&
        CursorY<Piece.Y+Piece.Height &&
        Piece.LayOut>PieceHandler::__DUMMY__ && Piece.LayOut<PieceHandler::__DUMMY2__)
        goto JumpIn;

      if (PromptWidth && CursorX>=Piece.PromptX &&
        CursorY>=Piece.PromptY &&
        CursorX<Piece.PromptX+PromptWidth &&
        CursorY==Piece.PromptY &&
        Piece.LayOut>PieceHandler::__DUMMY__ && Piece.LayOut<PieceHandler::__DUMMY2__)
      {
        PlacePrompter(Piece);
        return 1;
      }
    }

    // If no elements under cursor, jump to remainer of objects in queue

    for (i=NumberPieces-1;i>=0;i--)
    {

JumpIn:

      PieceHandler &Piece=*Pieces[i];

      if (CursorX>=Piece.X && CursorY>=Piece.Y &&
        CursorX<Piece.X+Piece.Width && CursorY<Piece.Y+Piece.Height)
      {
        if (Moused && CursorY==Piece.Y+Piece.Height-1 &&
          CursorX==Piece.X+Piece.Width-1 && Piece.LayOut<PieceHandler::__DUMMY__)
        {
          SizeObject(Moused);
          return 1;
        }

        RemoveTheMenus();

        Blaze.HelpLine(0,
          (!PlaceObject)?"Use the keyboard or mouse to move the object (Esc aborts)":
          "Use the keyboard or mouse to place the copied object (Esc aborts)");

        MousePosition(X+Piece.X+1,Y+Piece.Y+1);
        MouseLocate();

        Event EventHandler;

        int SaveX=Piece.X;
        int SaveY=Piece.Y;
        int MouseX=MouseHorizontal;
        int MouseY=MouseVertical;

        for (;;)
        {
          switch (EventHandler.GetEvent())
          {
            case kbUp:
              if (!Piece.Y)
                continue;
              Piece.Y--;
              VirtualizedInterior();
              break;

            case kbDown:
              if (Piece.Y==Blaze.WhatWinHeight()-1)
                break;
              Piece.Y++;
              VirtualizedInterior();
              break;

            case kbLeft:
              if (!Piece.X)
                continue;
              Piece.X--;
              VirtualizedInterior();
              break;

            case kbRight:
              if (Piece.X==Blaze.WhatWinWidth()-1)
                break;
              Piece.X++;
              VirtualizedInterior();
              break;

            case MousedEvent:
              if (MouseEvent&MouseMoved)
              {
                int NewX=MouseHorizontal-MouseX;
                int NewY=MouseVertical-MouseY;
                Piece.X+=NewX;
                Piece.Y+=NewY;
                MouseX=MouseHorizontal;
                MouseY=MouseVertical;

                if (Piece.X<0)
                  Piece.X=0;
                if (Piece.Y<0)
                  Piece.Y=0;

                if (Piece.X>Blaze.WhatWinWidth()-1)
                  Piece.X=Blaze.WhatWinWidth()-1;
                if (Piece.Y>Blaze.WhatWinHeight()-1)
                  Piece.Y=Blaze.WhatWinHeight()-1;

                if (MouseX<X+1 || MouseX>=X+Width-1 ||
                 MouseY<Y+1 || MouseY>=Y+Height-1)
                {
                  MousePosition(X+Piece.X+1,Y+Piece.Y+1);
                  MouseLocate();
                  MouseX=MouseHorizontal;
                  MouseY=MouseVertical;
                }

                VirtualizedInterior();
              }
              if (MouseEvent&MouseLeftButtonRelease)
                return 1;
              break;

            case kbCr:
              return 1;

            case kbEsc:
              Piece.X=SaveX;
              Piece.Y=SaveY;
              VirtualizedInterior();
              return 0;
          }
        }
      }
    }
  }

  if (Moused)
    return 0;

  InfoBox NothingFound;

  NothingFound
    + "Sorry, there is nothing below"
    + "the cursor that can be moved.";

  NothingFound.Title("Nothing to Move");
  NothingFound.UseInfoBox();

  return 0;
}

//-------------------------------------------------------------------------
//
// Change the color of an object on the dialog
//
//-------------------------------------------------------------------------

void DialogWindow::ColorObject()
{
  if (NumberPieces)
  {
    for (int i=NumberPieces-1;i>=0;i--)
    {
      PieceHandler &Piece=*Pieces[i];

      if (CursorX>=Piece.X && CursorY>=Piece.Y &&
        CursorX<Piece.X+Piece.Width && CursorY<Piece.Y+Piece.Width)
      {
        RemoveTheMenus();

        Piece.Color=CurrentColor;

        VirtualizedInterior();

        return;
      }
    }
  }

  InfoBox NothingFound;

  NothingFound
    + "Sorry, there is nothing below"
    + "the cursor that can be colored.";

  NothingFound.Title("Nothing to Color");
  NothingFound.UseInfoBox();
}

//-------------------------------------------------------------------------
//
// Change the size of an object on the dialog
//
//-------------------------------------------------------------------------

void DialogWindow::SizeObject(int Moused)
{
  if (NumberPieces)
  {
    // Give elements priority for editation

    for (int i=NumberPieces-1;i>=0;i--)
    {
      PieceHandler &Piece=*Pieces[i];

      int PromptWidth=0;

      if (Piece.Prompter && *Piece.Prompter)
      {
        PromptWidth=strlen(Piece.Prompter)-(strchr(Piece.Prompter,'~')?1:0);
      }

      if ((CursorX>=Piece.X &&
        CursorY>=Piece.Y &&
        CursorX<Piece.X+Piece.Width &&
        CursorY<Piece.Y+Piece.Height &&
        Piece.LayOut>PieceHandler::__DUMMY__) ||
        (PromptWidth && CursorX>=Piece.PromptX &&
        CursorY>=Piece.PromptY &&
        CursorX<Piece.PromptX+PromptWidth &&
        CursorY==Piece.PromptY &&
        Piece.LayOut>PieceHandler::__DUMMY__))
      {
        EditElement(Piece);
        return;
      }
    }

    for (i=NumberPieces-1;i>=0;i--)
    {
      PieceHandler &Piece=*Pieces[i];

      if ((Moused && CursorY==Piece.Y+Piece.Height-1 && CursorX==Piece.X+Piece.Width-1)
        || (!Moused && (CursorX>=Piece.X && CursorY>=Piece.Y &&
           CursorX<Piece.X+Piece.Width && CursorY<Piece.Y+Piece.Height)))
      {
        RemoveTheMenus();

        Blaze.HelpLine(0,"Use the keyboard or mouse to size the object (Esc aborts)");
        MouseLocate();

        Event EventHandler;

        int SaveWidth=Piece.Width;
        int SaveHeight=Piece.Height;
        int MouseX=MouseHorizontal;
        int MouseY=MouseVertical;

        for (;;)
        {
          switch (EventHandler.GetEvent())
          {
            case kbUp:
              Piece.Size(0,-1);
              VirtualizedInterior();
              break;

            case kbDown:
              Piece.Size(0,1);
              if (Piece.Y+Piece.Height>Blaze.WhatWinHeight()-1)
                Piece.Size(0,-((Piece.Y+Piece.Height)-Blaze.WhatWinHeight()));
              VirtualizedInterior();
              break;

            case kbLeft:
              Piece.Size(-1,0);
              VirtualizedInterior();
              break;

            case kbRight:
              Piece.Size(1,0);
              if (Piece.X+Piece.Width>Blaze.WhatWinWidth()-1)
                Piece.Size(-((Piece.X+Piece.Width)-Blaze.WhatWinWidth()),0);
              VirtualizedInterior();
              break;

            case MousedEvent:
              if (MouseEvent&MouseMoved)
              {
                int NewX=MouseHorizontal-MouseX;
                int NewY=MouseVertical-MouseY;
                MouseX=MouseHorizontal;
                MouseY=MouseVertical;
                Piece.Size(NewX,NewY);

                if (Piece.X+Piece.Width>Blaze.WhatWinWidth()-1)
                  Piece.Size(-((Piece.X+Piece.Width)-Blaze.WhatWinWidth()),0);
                if (Piece.Y+Piece.Height>Blaze.WhatWinHeight()-1)
                  Piece.Size(0,-((Piece.Y+Piece.Height)-Blaze.WhatWinHeight()));

                if (MouseX!=X+Piece.X+Piece.Width || MouseY!=Y+Piece.Y+Piece.Height)
                {
                  MousePosition(X+Piece.X+Piece.Width,Y+Piece.Y+Piece.Height);
                  MouseLocate();
                  MouseX=MouseHorizontal;
                  MouseY=MouseVertical;
                }

                VirtualizedInterior();
              }
              if (MouseEvent&MouseLeftButtonRelease)
                return;
              break;

            case kbCr:
              return;

            case kbEsc:
              Piece.Width=SaveWidth;
              Piece.Height=SaveHeight;
              VirtualizedInterior();
              return;
          }
        }
      }
    }
  }

  if (Moused)
    return;

  InfoBox NothingFound;

  NothingFound
    + "Sorry, there is nothing below"
    + "the cursor that can be sized.";

  NothingFound.Title("Nothing to Size");
  NothingFound.UseInfoBox();
}

//-------------------------------------------------------------------------
//
// Bring an object to the front of the dialog
//
//-------------------------------------------------------------------------

void DialogWindow::BringFront()
{
  if (NumberPieces>1)
  {
    for (int i=NumberPieces-1;i>=0;i--)
    {
      PieceHandler &Piece=*Pieces[i];

      if (CursorX>=Piece.X && CursorY>=Piece.Y &&
          CursorX<Piece.X+Piece.Width && CursorY<Piece.Y+Piece.Height &&
          Piece.LayOut<PieceHandler::__DUMMY__)
      {
        RemoveTheMenus();

        if (i==NumberPieces-1)
           return;

        PieceHandler *Hold=Pieces[i];

        movmem(&Pieces[i+1],&Pieces[i],(NumberPieces-i-1)*sizeof(PieceHandler *));

        Pieces[NumberPieces-1]=Hold;

        VirtualizedInterior();

        return;
      }
    }
  }

  InfoBox NothingFound;

  NothingFound
    + "Sorry, there isn\'t a drawn"
    + "object below the cursor that"
    + "can be pulled forward.";

  NothingFound.Title("Nothing to Pull");
  NothingFound.UseInfoBox();
}

//-------------------------------------------------------------------------
//
// Bring an object to the back of the dialog
//
//-------------------------------------------------------------------------

void DialogWindow::PushBack()
{
  if (NumberPieces>1)
  {
    for (int i=NumberPieces-1;i>=0;i--)
    {
      PieceHandler &Piece=*Pieces[i];

      if (CursorX>=Piece.X && CursorY>=Piece.Y &&
          CursorX<Piece.X+Piece.Width && CursorY<Piece.Y+Piece.Height &&
          Piece.LayOut<PieceHandler::__DUMMY__)
      {
        RemoveTheMenus();

        if (!i)
          return;

        PieceHandler *Hold=Pieces[i];

        movmem(&Pieces[0],&Pieces[1],i*sizeof(PieceHandler *));

        Pieces[0]=Hold;

        VirtualizedInterior();

        return;
      }
    }
  }

  InfoBox NothingFound;

  NothingFound
    + "Sorry, there isn\'t a drawn"
    + "object below the cursor that"
    + "can be pushed back.";

  NothingFound.Title("Nothing to Push");
  NothingFound.UseInfoBox();
}

//-------------------------------------------------------------------------
//
// Duplicate an object to another location
//
//-------------------------------------------------------------------------

void DialogWindow::CopyObject()
{
  if (NumberPieces)
  {
    // Give elements priority for copying

    int PromptWidth=0;

    for (int i=NumberPieces-1;i>=0;i--)
    {
      PieceHandler &Piece=*Pieces[i];

      if (Piece.Prompter && *Piece.Prompter)
      {
        PromptWidth=strlen(Piece.Prompter)-(strchr(Piece.Prompter,'~')?1:0);
      }

      if ((CursorX>=Piece.X &&
        CursorY>=Piece.Y &&
        CursorX<Piece.X+Piece.Width &&
        CursorY<Piece.Y+Piece.Height &&
        Piece.LayOut>PieceHandler::__DUMMY__ && Piece.LayOut<PieceHandler::__DUMMY2__) ||
       (PromptWidth && CursorX>=Piece.PromptX &&
        CursorY>=Piece.PromptY &&
        CursorX<Piece.PromptX+PromptWidth &&
        CursorY==Piece.PromptY &&
        Piece.LayOut>PieceHandler::__DUMMY__ && Piece.LayOut<PieceHandler::__DUMMY2__))
          goto JumpIn;
    }

    PromptWidth=0;

    // If no elements under cursor, jump to remainer of objects in queue

    for (i=NumberPieces-1;i>=0;i--)
    {

JumpIn:

      PieceHandler &Piece=*Pieces[i];

      if ((CursorX>=Piece.X && CursorY>=Piece.Y &&
          CursorX<Piece.X+Piece.Width && CursorY<Piece.Y+Piece.Height) ||
          PromptWidth)
      {
        RemoveTheMenus();

        Pieces=(PieceHandler **)realloc(Pieces,++NumberPieces*sizeof(char *));

        switch (Piece.LayOut)
        {
          case PieceHandler::Box:
            Pieces[NumberPieces-1]=new Box(Piece);
            break;

          case PieceHandler::FilledBox:
            Pieces[NumberPieces-1]=new FilledBox(Piece);
            break;

          case PieceHandler::HorizontalLine:
            Pieces[NumberPieces-1]=new HorizontalLine(Piece);
            break;

          case PieceHandler::VerticalLine:
            Pieces[NumberPieces-1]=new VerticalLine(Piece);
            break;

          case PieceHandler::Shadow:
            Pieces[NumberPieces-1]=new Shadow(Piece);
            break;

          case PieceHandler::EraseArea:
            Pieces[NumberPieces-1]=new EraseArea(Piece);
            break;

          case PieceHandler::ColorizeArea:
            Pieces[NumberPieces-1]=new ColorizeArea(Piece);
            break;

          case PieceHandler::Character:
            Pieces[NumberPieces-1]=new Character(Piece);
            break;

          case PieceHandler::Integer:
            Pieces[NumberPieces-1]=new Integer(Piece);
            break;

          case PieceHandler::Long:
            Pieces[NumberPieces-1]=new Long(Piece);
            break;

          case PieceHandler::Float:
            Pieces[NumberPieces-1]=new Float(Piece);
            break;

          case PieceHandler::Double:
            Pieces[NumberPieces-1]=new Double(Piece);
            break;

          case PieceHandler::Bcd:
            Pieces[NumberPieces-1]=new Bcd(Piece);
            break;

          case PieceHandler::Check:
            Pieces[NumberPieces-1]=new Check(Piece);
            break;

          case PieceHandler::Push:
            Pieces[NumberPieces-1]=new Push(Piece);
            break;

          case PieceHandler::GroupHeading:
            Pieces[NumberPieces-1]=new GroupHeading(Piece);
            break;

          case PieceHandler::HRadio:
            Pieces[NumberPieces-1]=new HRadio(Piece);
            break;

          case PieceHandler::VRadio:
            Pieces[NumberPieces-1]=new VRadio(Piece);
            break;

          case PieceHandler::PickGeneric:
            Pieces[NumberPieces-1]=new PickGeneric(Piece);
            break;
        }

        if (Piece.LayOut>PieceHandler::__DUMMY__)
        {
          PieceHandler &PieceCopy=*Pieces[NumberPieces-1];

          if (Piece.Mask)
          {
            PieceCopy.Mask=new char[50];
            strcpy(PieceCopy.Mask,Piece.Mask);
          }

          if (Piece.Variable)
          {
            PieceCopy.Variable=new char[50];
            strcpy(PieceCopy.Variable,Piece.Variable);
          }

          if (Piece.Prompter)
          {
            PieceCopy.Prompter=new char[50];
            strcpy(PieceCopy.Prompter,Piece.Prompter);
          }

          if (Piece.HotKey)
          {
            PieceCopy.HotKey=new char[30];
            strcpy(PieceCopy.HotKey,Piece.HotKey);
          }

          if (Piece.Text)
          {
            PieceCopy.Text=new char[50];
            strcpy(PieceCopy.Text,Piece.Text);
          }

          if (Piece.Constant)
          {
            PieceCopy.Constant=new char[50];
            strcpy(PieceCopy.Constant,Piece.Constant);
          }

          if (Piece.Help)
          {
            PieceCopy.Help=new char[65];
            strcpy(PieceCopy.Help,Piece.Help);
          }

          if (Piece.DerivedClass)
          {
            PieceCopy.DerivedClass=new char[50];
            strcpy(PieceCopy.DerivedClass,Piece.DerivedClass);
          }

          if (Piece.Elements)
          {
            PieceCopy.Elements=new char*[10];
            for (int i=0;i<10;i++)
            {
              PieceCopy.Elements[i]=new char[50];
              strcpy(PieceCopy.Elements[i],Piece.Elements[i]);
            }
          }
        }

        VirtualizedInterior();

        if (!MoveObject(0,1))
        {
          delete Pieces[--NumberPieces];
          VirtualizedInterior();
        }

        return;
      }
    }
  }

  InfoBox NothingFound;

  NothingFound
    + "Sorry, there isn\'t an"
    + "object below the cursor"
    + "that can be copied.";

  NothingFound.Title("Nothing to Copy");
  NothingFound.UseInfoBox();
}

//-------------------------------------------------------------------------
//
// Remove an object from the dialog
//
//-------------------------------------------------------------------------

void DialogWindow::DeleteObject()
{
  if (NumberPieces)
  {
    // Give elements priority for deletion

    int PromptWidth=0;

    for (int i=NumberPieces-1;i>=0;i--)
    {
      PieceHandler &Piece=*Pieces[i];

      if (Piece.Prompter && *Piece.Prompter)
      {
        PromptWidth=strlen(Piece.Prompter)-(strchr(Piece.Prompter,'~')?1:0);
      }

      if ((CursorX>=Piece.X &&
        CursorY>=Piece.Y &&
        CursorX<Piece.X+Piece.Width &&
        CursorY<Piece.Y+Piece.Height &&
        Piece.LayOut>PieceHandler::__DUMMY__ && Piece.LayOut<PieceHandler::__DUMMY2__) ||
       (PromptWidth && CursorX>=Piece.PromptX &&
        CursorY>=Piece.PromptY &&
        CursorX<Piece.PromptX+PromptWidth &&
        CursorY==Piece.PromptY &&
        Piece.LayOut>PieceHandler::__DUMMY__ && Piece.LayOut<PieceHandler::__DUMMY2__))
          goto JumpIn;
    }

    PromptWidth=0;

    // If no elements under cursor, jump to remainer of objects in queue

    for (i=NumberPieces-1;i>=0;i--)
    {

JumpIn:

      PieceHandler &Piece=*Pieces[i];

      if ((CursorX>=Piece.X && CursorY>=Piece.Y &&
        CursorX<Piece.X+Piece.Width && CursorY<Piece.Y+Piece.Height)
        || PromptWidth)
      {
        RemoveTheMenus();

        delete Pieces[i];

        if (i!=NumberPieces-1)
          movmem(&Pieces[i+1],&Pieces[i],(NumberPieces-i-1)*sizeof(PieceHandler *));

        NumberPieces--;

        VirtualizedInterior();

        return;
      }
    }
  }

  InfoBox NothingFound;

  NothingFound
    + "Sorry, there is nothing below"
    + "the cursor that can be deleted.";

  NothingFound.Title("Nothing to Delete");
  NothingFound.UseInfoBox();
}

//-------------------------------------------------------------------------
//
// Recolorize text within a region
//
//-------------------------------------------------------------------------

void DialogWindow::ColorText()
{
  RemoveTheMenus();

  Blaze.HelpLine(0,"Use the keyboard or mouse to select the region (Esc aborts)");

  MousePosition(X+CursorX+1,Y+CursorY+1);
  MouseLocate();

  Event EventHandler;

  int MouseX=MouseHorizontal;
  int MouseY=MouseVertical;

  int Width=1;
  int Height=1;

  for (;;)
  {
    Blaze.BoxAttribute(CursorX,CursorY,Width,Height,CurrentColor);
    switch (EventHandler.GetEvent())
    {
      case kbUp:
        if (Height==1)
          continue;
        Height--;
        VirtualizedInterior();
        break;

      case kbDown:
        if (CursorY+Height>=Blaze.WhatWinHeight()-1)
          break;
        Height++;
        VirtualizedInterior();
        break;

      case kbLeft:
        if (Width==1)
          continue;
        Width--;
        VirtualizedInterior();
        break;

      case kbRight:
        if (CursorX+Width>=Blaze.WhatWinWidth()-1)
          break;
        Width++;
        VirtualizedInterior();
        break;

      case MousedEvent:
        if (MouseEvent&MouseMoved)
        {
          int NewX=MouseHorizontal-MouseX;
          int NewY=MouseVertical-MouseY;
          MouseX=MouseHorizontal;
          MouseY=MouseVertical;
          Width+=NewX;
          Height+=NewY;
          if (Width<1)
            Width=1;
          if (Height<1)
            Height=1;

          if (CursorX+Width>Blaze.WhatWinWidth()-1)
            Width=Blaze.WhatWinWidth()-CursorX;
          if (CursorY+Height>Blaze.WhatWinHeight()-1)
            Height=Blaze.WhatWinHeight()-CursorY;

          if (MouseX!=X+CursorX+Width || MouseY!=Y+CursorY+Height)
          {
            MousePosition(X+CursorX+Width,Y+CursorY+Height);
            MouseLocate();
            MouseX=MouseHorizontal;
            MouseY=MouseVertical;
          }

          VirtualizedInterior();
        }
        if (MouseEvent&MouseLeftButtonRelease)
          goto ColorChange;
        break;

      case kbCr:
        goto ColorChange;

      case kbEsc:
        VirtualizedInterior();
        return;
    }
  }

ColorChange:

  for (int Y=CursorY;Y<CursorY+Height;Y++)
    for (int X=(CursorX*2)+1;X<((CursorX+Width)*2);X+=2)
      *(Interior[Y]+X)=CurrentColor;

  VirtualizedInterior();
}

//-------------------------------------------------------------------------
//
// Copy text within a region to another location
//
//-------------------------------------------------------------------------

void DialogWindow::CopyText()
{
  RemoveTheMenus();

  Blaze.HelpLine(0,"Use the keyboard or mouse to select the copy region (Esc aborts)");
  MousePosition(X+CursorX+1,Y+CursorY+1);
  MouseLocate();

  Event EventHandler;

  int MouseX=MouseHorizontal;
  int MouseY=MouseVertical;

  int Width=1;
  int Height=1;

  for (;;)
  {
    Blaze.BoxAttribute(CursorX,CursorY,Width,Height,bRed|fYellow);
    switch (EventHandler.GetEvent())
    {
      case kbUp:
        if (Height==1)
          continue;
        Height--;
        VirtualizedInterior();
        break;

      case kbDown:
        if (CursorY+Height>=Blaze.WhatWinHeight()-1)
          break;
        Height++;
        VirtualizedInterior();
        break;

      case kbLeft:
        if (Width==1)
          continue;
        Width--;
        VirtualizedInterior();
        break;

      case kbRight:
        if (CursorX+Width>=Blaze.WhatWinWidth()-1)
          break;
        Width++;
        VirtualizedInterior();
        break;

      case MousedEvent:
        if (MouseEvent&MouseMoved)
        {
          int NewX=MouseHorizontal-MouseX;
          int NewY=MouseVertical-MouseY;
          MouseX=MouseHorizontal;
          MouseY=MouseVertical;
          Width+=NewX;
          Height+=NewY;
          if (Width<1)
            Width=1;
          if (Height<1)
            Height=1;
          VirtualizedInterior();

          if (CursorX+Width>Blaze.WhatWinWidth()-1)
            Width=Blaze.WhatWinWidth()-CursorX;
          if (CursorY+Height>Blaze.WhatWinHeight()-1)
            Height=Blaze.WhatWinHeight()-CursorY;

          if (MouseX!=X+CursorX+Width || MouseY!=Y+CursorY+Height)
          {
            MousePosition(X+CursorX+Width,Y+CursorY+Height);
            MouseLocate();
            MouseX=MouseHorizontal;
            MouseY=MouseVertical;
          }
        }
        if (MouseEvent&MouseLeftButtonRelease)
          goto CopyIt;
        break;

      case kbCr:
        goto CopyIt;

      case kbEsc:
        VirtualizedInterior();
        return;
    }
  }

CopyIt:

  int CurrentX=CursorX;
  int CurrentY=CursorY;

  char (*DuplicateInterior)[400]=new char[61][sizeof(DuplicateInterior[0])];

  memcpy(DuplicateInterior,Interior,sizeof(DuplicateInterior[0])*60);

  Blaze.HelpLine(0,"Use the keyboard or mouse to select the copy location (Esc aborts)");

  int WinX=X, WinY=Y;
  MousePosition(X+CursorX+1,Y+CursorY+1);
  MouseLocate();

  MouseX=MouseHorizontal;
  MouseY=MouseVertical;

  for (;;)
  {
    memcpy(Interior,DuplicateInterior,sizeof(DuplicateInterior[0])*60);

    for (int Y=CursorY,Z=CurrentY;Y<CursorY+Height;Y++,Z++)
    {
      for (int X=CursorX,U=CurrentX;X<CursorX+Width;X++,U++)
      {
        if (*(DuplicateInterior[Y]+(X*2)))
        {
          *(Interior[Z]+(U*2))=*(DuplicateInterior[Y]+(X*2));
          *(Interior[Z]+(U*2)+1)=*(DuplicateInterior[Y]+(X*2)+1);
        }
      }
    }

    VirtualizedInterior();
    Blaze.BoxAttribute(CurrentX,CurrentY,Width,Height,bRed|fYellow);

    switch (EventHandler.GetEvent())
    {
      case kbUp:
        if (!CurrentY)
          continue;
        CurrentY--;
        break;

      case kbDown:
        if (CurrentY>=Blaze.WhatWinHeight()-1)
          CurrentY=Blaze.WhatWinHeight()-1;
        CurrentY++;
        break;

      case kbLeft:
        if (!CurrentX)
          continue;
        CurrentX--;
        break;

      case kbRight:
        if (CurrentX>=Blaze.WhatWinWidth()-1)
          CurrentX=Blaze.WhatWinWidth()-1;
        CurrentX++;
        break;

      case MousedEvent:
        if (MouseEvent&MouseMoved)
        {
          int NewX=MouseHorizontal-MouseX;
          int NewY=MouseVertical-MouseY;
          MouseX=MouseHorizontal;
          MouseY=MouseVertical;
          CurrentX+=NewX;
          CurrentY+=NewY;
          if (CurrentY<0)
            CurrentY=0;
          if (CurrentX<0)
            CurrentX=1;

          if (CurrentX>Blaze.WhatWinWidth()-1)
            CurrentX=Blaze.WhatWinWidth()-1;
          if (CurrentY>Blaze.WhatWinHeight()-1)
            CurrentY=Blaze.WhatWinHeight()-1;

          if (MouseX!=WinX+CurrentX+1 || MouseY!=WinY+CurrentY+1)
          {
            MousePosition(WinX+CurrentX+1,WinY+CurrentY+1);
            MouseLocate();
            MouseX=MouseHorizontal;
            MouseY=MouseVertical;
          }
        }
        if (MouseEvent&MouseLeftButtonRelease)
          goto OutaHere;
        break;

      case kbCr:
        goto OutaHere;

      case kbEsc:
        memcpy(Interior,DuplicateInterior,sizeof(DuplicateInterior[0])*60);
        delete DuplicateInterior;
        VirtualizedInterior();
        return;
    }
  }

OutaHere:

  delete DuplicateInterior;

  VirtualizedInterior();
}

//-------------------------------------------------------------------------
//
// Move text within a region to another location and remove it from the
// original location
//
//-------------------------------------------------------------------------

void DialogWindow::MoveText()
{
  RemoveTheMenus();

  Blaze.HelpLine(0,"Use the keyboard or mouse to select the move region (Esc aborts)");
  MousePosition(X+CursorX+1,Y+CursorY+1);
  MouseLocate();

  Event EventHandler;

  int MouseX=MouseHorizontal;
  int MouseY=MouseVertical;

  int Width=1;
  int Height=1;

  for (;;)
  {
    Blaze.BoxAttribute(CursorX,CursorY,Width,Height,bRed|fYellow);
    switch (EventHandler.GetEvent())
    {
      case kbUp:
        if (Height==1)
          continue;
        Height--;
        VirtualizedInterior();
        break;

      case kbDown:
        if (CursorY+Height>=Blaze.WhatWinHeight()-1)
          Height=Blaze.WhatWinHeight()-CursorY;
        Height++;
        VirtualizedInterior();
        break;

      case kbLeft:
        if (Width==1)
          continue;
        Width--;
        VirtualizedInterior();
        break;

      case kbRight:
        if (CursorX+Width>=Blaze.WhatWinWidth()-1)
          Width=Blaze.WhatWinWidth()-CursorX;
        Width++;
        VirtualizedInterior();
        break;

      case MousedEvent:
        if (MouseEvent&MouseMoved)
        {
          int NewX=MouseHorizontal-MouseX;
          int NewY=MouseVertical-MouseY;
          MouseX=MouseHorizontal;
          MouseY=MouseVertical;
          Width+=NewX;
          Height+=NewY;
          if (Width<1)
            Width=1;
          if (Height<1)
            Height=1;
          VirtualizedInterior();

          if (CursorX+Width>Blaze.WhatWinWidth()-1)
            Width=Blaze.WhatWinWidth()-CursorX;
          if (CursorY+Height>Blaze.WhatWinHeight()-1)
            Height=Blaze.WhatWinHeight()-CursorY;

          if (MouseX!=X+CursorX+Width || MouseY!=Y+CursorY+Height)
          {
            MousePosition(X+CursorX+Width,Y+CursorY+Height);
            MouseLocate();
            MouseX=MouseHorizontal;
            MouseY=MouseVertical;
          }
        }
        if (MouseEvent&MouseLeftButtonRelease)
          goto CopyIt;
        break;

      case kbCr:
        goto CopyIt;

      case kbEsc:
        VirtualizedInterior();
        return;
    }
  }

CopyIt:

  int CurrentX=CursorX;
  int CurrentY=CursorY;

  char (*DuplicateInterior)[400]=new char[61][sizeof(DuplicateInterior[0])];

  memcpy(DuplicateInterior,Interior,sizeof(DuplicateInterior[0])*60);

  Blaze.HelpLine(0,"Use the keyboard or mouse to select the move location (Esc aborts)");

  int WinX=X, WinY=Y;
  MousePosition(X+CursorX+1,Y+CursorY+1);
  MouseLocate();

  MouseX=MouseHorizontal;
  MouseY=MouseVertical;

  for (;;)
  {
    memcpy(Interior,DuplicateInterior,sizeof(DuplicateInterior[0])*60);

    for (int YY=CursorY;YY<CursorY+Height;YY++)
      memset((Interior[YY]+(CursorX*2)),0,Width*2);

    for (int Y=CursorY,Z=CurrentY;Y<CursorY+Height;Y++,Z++)
    {
      for (int X=CursorX,U=CurrentX;X<CursorX+Width;X++,U++)
      {
        if (*(DuplicateInterior[Y]+(X*2)))
        {
          *(Interior[Z]+(U*2))=*(DuplicateInterior[Y]+(X*2));
          *(Interior[Z]+(U*2)+1)=*(DuplicateInterior[Y]+(X*2)+1);
        }
      }
    }

    VirtualizedInterior();
    Blaze.BoxAttribute(CurrentX,CurrentY,Width,Height,bRed|fYellow);

    switch (EventHandler.GetEvent())
    {
      case kbUp:
        if (!CurrentY)
          continue;
        CurrentY--;
        break;

      case kbDown:
        if (CurrentY>=Blaze.WhatWinHeight()-1)
          CurrentY=Blaze.WhatWinHeight()-1;
        CurrentY++;
        break;

      case kbLeft:
        if (!CurrentX)
          continue;
        CurrentX--;
        break;

      case kbRight:
        if (CurrentX>=Blaze.WhatWinWidth()-1)
          CurrentX=Blaze.WhatWinWidth()-1;
        CurrentX++;
        break;

      case MousedEvent:
        if (MouseEvent&MouseMoved)
        {
          int NewX=MouseHorizontal-MouseX;
          int NewY=MouseVertical-MouseY;
          MouseX=MouseHorizontal;
          MouseY=MouseVertical;
          CurrentX+=NewX;
          CurrentY+=NewY;
          if (CurrentY<0)
            CurrentY=0;
          if (CurrentX<0)
            CurrentX=1;

          if (CurrentX>Blaze.WhatWinWidth()-1)
            CurrentX=Blaze.WhatWinWidth()-1;
          if (CurrentY>Blaze.WhatWinHeight()-1)
            CurrentY=Blaze.WhatWinHeight()-1;

          if (MouseX!=WinX+CurrentX+1 || MouseY!=WinY+CurrentY+1)
          {
            MousePosition(WinX+CurrentX+1,WinY+CurrentY+1);
            MouseLocate();
            MouseX=MouseHorizontal;
            MouseY=MouseVertical;
          }
        }
        if (MouseEvent&MouseLeftButtonRelease)
          goto OutaHere;
        break;

      case kbCr:
        goto OutaHere;

      case kbEsc:
        memcpy(Interior,DuplicateInterior,sizeof(DuplicateInterior[0])*60);
        delete DuplicateInterior;
        VirtualizedInterior();
        return;
    }
  }

OutaHere:

  delete DuplicateInterior;

  VirtualizedInterior();
}
