char InvBuf[]=
   {CSI,'7',0x6d,NULL,CSI,'0',0x6d};
char Inv[]=
   {CSI,'7',0x6d,NULL};
char Norm[]=
   {CSI,'0',0x6d,NULL};

struct LineItem *InvItem;

MovedMouse(x,y)   /*The mouse was moved! Record its new position*/
int x,y;
{
   LastX=PtrX;
   LastY=PtrY;
   PtrX=(x/8)+1;
   PtrY=(y/8)+1;
}

HandleButton(Seconds,Micros)  /*Handle a button press*/
int Seconds,Micros;
{
   int status;
   static int LastSeconds=1,LastMicros=1,DoubClicked=FALSE;
   static UBYTE ButtonX,ButtonY;

   /*If the user double-clicked (the mouse button), start or modify*/
   /*a highlighted block*/
   if(DoubleClick(LastSeconds,LastMicros,Seconds,Micros) &&
         PtrY==LastY && !DoubClicked)
      {
      PtrX=ButtonX;
      PtrY=ButtonY;
      DoubClicked=TRUE;
      HandleInvs();
      BLastX=PtrX;
      BLastY=PtrY;
      }
   else  /*Otherwise, just move the cursor accordingly*/
      if(PtrY > 0 && PtrY <= SCRNHEIGHT)
         {
         ButtonX=PtrX;
         ButtonY=PtrY;
         DoubClicked=FALSE;
         if(PtrY != InvY && InvsMode > NOINV)
            EndLineInvs();
         if(PtrY-CurY < 0)
            status=MoveBack(-(PtrY-CurY));
         else
            status=MoveForward(PtrY-CurY);
         if(status==FALSE)
            return(FALSE);

         if(PtrX > MaxX(CurrentItem))
            CurX=MaxX(CurrentItem);
         else
            if(PtrX < MinX(CurrentItem))
               CurX=MinX(CurrentItem);
            else
               CurX=PtrX;
         PlotCursor(CurX,PtrY);
         }
   LastSeconds=Seconds;
   LastMicros=Micros;
}

HandleInvs() /*Handle a modification or creation of a highlighted block*/
{
   if(InvsMode==NOINV)
      if(PtrX >= MinX(CurrentItem) && PtrX <= MaxX(CurrentItem))
         HandleLineInvs();
      else
         HandleBlockInvs();
   else
      if(InvsMode > NOINV)
         HandleLineInvs();
      else
         HandleBlockInvs();
}

HandleBlockInvs() /*Handle the inverse of a block of lines*/
{
   int X,Y;

   if(InvsMode==NOINV)
      {
      InvY=EndIY=CurY;
      WriteConsole(Inv,-1);
      PlotCursor(1,CurY);
      PrintItem(CurrentItem);
      WriteConsole(Norm,-1);
      EndIItem=StartIItem=(struct LineItem *)CurrentItem;
      PlotCursor(MinX(CurrentItem),CurY);
      InvsMode=BLOCK_PENDING;
      return(TRUE);
      }

   if(InvsMode==BLOCK_PENDING)
      {
      if(PtrY == BLastY)
         {
         EndBlockInvs();
         return(TRUE);
         }

      if(PtrY > BLastY)
         {
         EndIItem=(struct LineItem *)CurrentItem;
         PlotCursor(1,BLastY+1);
         RvsBlock(StartIItem->NextItem,EndIItem);
         EndIY=CurY=PtrY;
         InvsMode=BLOCK_DOWN;
         PlotCursor(MinX(EndIItem),CurY);
         }

      if(PtrY < BLastY)
         {
         EndIItem=(struct LineItem *)CurrentItem;
         EndIY=CurY;
         RvsBlock(EndIItem,StartIItem->PrevItem);
         PlotCursor(MinX(EndIItem),EndIY);
         InvsMode=BLOCK_UP;
         }
      return(TRUE);
      }

   if(InvsMode == BLOCK_DOWN)
      {
      if(PtrY > BLastY)
         {
         PlotCursor(1,BLastY+1);
         RvsBlock(EndIItem->NextItem,CurrentItem);
         EndIY=CurY=PtrY;
         EndIItem=(struct LineItem *)CurrentItem;
         PlotCursor(MinX(EndIItem),CurY);
         }
      if(PtrY < BLastY)
         {
         if(PtrY <= InvY)
            {
            EndBlockInvs(FALSE);
            return(TRUE);
            }
         EndIY=Y=CurY;
         X=CurX;
         PlotCursor(CurX,CurY+1);
         NormBlock(CurrentItem->NextItem,EndIItem);
         PlotCursor(X,Y);
         EndIItem=(struct LineItem *)CurrentItem;
         }
      }
   else
      {
      if(PtrY < BLastY)
         {
         EndIY=Y=CurY;
         RvsBlock(CurrentItem,EndIItem->PrevItem);
         PlotCursor(MinX(CurrentItem),Y);
         EndIItem=(struct LineItem *)CurrentItem;
         }
      if(PtrY > BLastY)
         {
         if(PtrY >= InvY)
            {
            EndBlockInvs();
            return(TRUE);
            }
         Y=CurY;
         PlotCursor(CurX,EndIY);
         NormBlock(EndIItem,CurrentItem->PrevItem);
         EndIItem=(struct LineItem *)CurrentItem;
         PlotCursor(MinX(CurrentItem),CurY+1);
         EndIY=CurY;
         }
      }
}

NormBlock(Start,End) /*Normalize a specified block of highlight*/
struct LineItem *Start,*End;
{
   struct LineItem *CurItem;

   CurItem=(struct LineItem *)Start;
   WriteConsole(Norm,-1);

   CurY--;
   while(CurItem != End->NextItem)
      {
      PlotCursor(1,CurY+1);
      PrintItem(CurItem);
      CurItem=(struct LineItem *)CurItem->NextItem;
      }
}

RvsBlock(Start,End)  /*Reverse a block*/
struct LineItem *Start,*End;
{
   struct LineItem *CurItem;

   CurItem=(struct LineItem *)Start;
   WriteConsole(Inv,-1);

   CurY--;
   while(CurItem != End->NextItem)
      {
      PlotCursor(1,CurY+1);
      PrintItem(CurItem);
      CurItem=(struct LineItem *)CurItem->NextItem;
      }
   WriteConsole(Norm,-1);
}

EndBlockInvs() /*End the highlight of a block of lines*/
{
   int Y=CurY;

   if(InvY > EndIY)
      {
      PlotCursor(1,EndIY);
      NormBlock(EndIItem,StartIItem);
      PlotCursor(MinX(CurrentItem),Y);
      }
   else
      {
      PlotCursor(1,InvY);
      NormBlock(StartIItem,EndIItem);
      PlotCursor(MinX(StartIItem),Y);
      }
   InvsMode=NOINV;
}

HandleLineInvs()  /*Handle the inverse of individual characters*/
{
   int NewEnd;

   if(PtrX < MinX(CurrentItem))
      PtrX=MinX(CurrentItem);
   else
      if(PtrX > MaxX(CurrentItem))
         PtrX=MaxX(CurrentItem);

   if(InvsMode==NOINV)
      {
      InvBuf[3]=CurrentItem->Text[PosInText(CurrentItem->Level)];
      WriteConsole(InvBuf,7);
      StartChar=EndChar=PosInText(CurrentItem->Level);
      PlotCursor(CurX,CurY);
      InvsMode=LINE_PENDING;
      InvY=CurY;
      InvItem=(struct LineItem *)CurrentItem;
      return(TRUE);
      }

   if(InvsMode==LINE_PENDING)
      {
      if(PtrX == BLastX)
         {
         EndLineInvs();
         return(TRUE);
         }

      if(PtrX > BLastX)
         {
         if(PtrX > BLastX+1)
            {
            EndChar=PosInText(InvItem->Level)-1;
            PlotCursor(BLastX+1,CurY);
            RvsText(StartChar+1,EndChar);
            CurX=CurX+EndChar-StartChar;
            }
         InvsMode=LINE_FWD;
         return(TRUE);
         }

      if(PtrX < BLastX)
         {
         EndChar=PosInText(InvItem->Level);
         RvsText(EndChar,StartChar-1);
         PlotCursor(PtrX,CurY);
         InvsMode=LINE_BACK;
         }
      return(TRUE);
      }
   else
      if(InvsMode==LINE_FWD)
         {
         if(PtrX > BLastX)
            {
            NewEnd=PtrX-MinX(InvItem)-1;
            PlotCursor(EndChar+MinX(InvItem),CurY);
            RvsText(EndChar,NewEnd);
            CurX=NewEnd+MinX(InvItem);
            EndChar=NewEnd;
            }

         if(PtrX < BLastX)
            if(PtrX-MinX(InvItem)<=StartChar)
               EndLineInvs();
            else
               {
               NewEnd=PtrX-MinX(InvItem);
               NormText(NewEnd,EndChar);
               PlotCursor(CurX,CurY);
               EndChar=NewEnd;
               }
         }
      else
         {
         if(PtrX < BLastX)
            {
            NewEnd=PtrX-MinX(InvItem);
            RvsText(NewEnd,EndChar);
            PlotCursor(CurX,CurY);
            EndChar=NewEnd;
            }

         if(PtrX > BLastX)
            if(PtrX-MinX(InvItem)>=StartChar)
               EndLineInvs();
            else
               {
               NewEnd=PtrX-MinX(InvItem)-1;
               PlotCursor(EndChar+MinX(InvItem),CurY);
               NormText(EndChar,NewEnd);
               CurX=NewEnd+MinX(InvItem);
               EndChar=NewEnd;
               PlotCursor(CurX+1,CurY);
               }
         }
}

RvsText(Start,End)   /*Highlight a block of text*/
int Start,End;
{
   char Buffer[80];
   int c,l;

   strcpy(Buffer,Inv);
   l=strlen(Buffer);

   for(c=l; c-l < End-Start+1 ; c++)
      {
      Buffer[c]=InvItem->Text[c+Start-l];
      }
   Buffer[c]=0;

   strcat(Buffer,Norm);

   WriteConsole(Inv,-1);
   WriteConsole(Buffer,c);
   WriteConsole(Norm,-1);
}


MoveBack(Number)  /*Move back in the item list a specified number of times*/
int Number;
{
   int c;

   for(c=0;c<Number;c++)
      {
      if(CurrentItem->PrevItem==NULL)
         return(FALSE);
      else
         CurrentItem=(struct LineItem *)CurrentItem->PrevItem;
      }
   return(TRUE);
}

MoveForward(Number)  /*Move forward in the item list a specifiecd*/
int Number;       /*number of times*/
{
   int c;
   struct LineItem *OrigItem;

   OrigItem=(struct LineItem *)CurrentItem;
   for(c=0;c<Number;c++)
      {
      if(CurrentItem->NextItem==NULL)
         {
         CurrentItem=(struct LineItem *)OrigItem;
         return(FALSE);
         }
      else
         CurrentItem=(struct LineItem *)CurrentItem->NextItem;
      }
   return(TRUE);
}

EndLineInvs()  /*End text inverse*/
{
   if(StartChar < EndChar)
      NormText(StartChar,EndChar);
   else
      NormText(EndChar,StartChar);
   InvsMode=NOINV;
}

NormText(Start,End)     /*Un-reverse text*/
int Start,End;
{
   int TempX,c;
   char Buffer[80];

   for(c=Start;c<=End;c++)
      Buffer[c-Start]=InvItem->Text[c];

   Buffer[c-Start]=0;

   TempX=CurX;
   PlotCursor(MinX(InvItem)+Start,InvY);
   WriteConsole(Buffer,-1);
   PlotCursor(TempX,InvY);
}

HandleDelBlock()  /*Delete a block of lines*/
{
   InvsMode=NOINV;

   if((StartIItem->PrevItem==NULL && EndIItem->NextItem==NULL) ||
         (StartIItem->NextItem==NULL && EndIItem->PrevItem==NULL))
      {
      NewAll();
      return(TRUE);
      }

   if(InvY <= BLastY)
      DelBlock(StartIItem,EndIItem,InvY,BLastY);
   else
      DelBlock(EndIItem,StartIItem,BLastY,InvY);
}

DelBlock(Start,End,StartY,EndY)  /*Delete a block of lines*/
struct LineItem *Start,*End;
int StartY,EndY;
{
   int TOS;

   if(Start==FirstScrnItem)
      TOS=TRUE;
   else
      TOS=FALSE;

   if(Start->PrevItem == NULL)
      {
      CurrentItem=FirstItem=FirstScrnItem=
            (struct LineItem *)End->NextItem;
      CurrentItem->PrevItem=NULL;
      RemItem(CurrentItem);
      AddItem(CurrentItem);
      TOS=FALSE;
      }
   else
      if(End->NextItem==NULL)
         {
         CurrentItem=LastItem=
               (struct LineItem *)Start->PrevItem;
         LastItem->NextItem=NULL;
         if(Start==FirstScrnItem)
            {
            FirstScrnItem=ScrnBtm=(struct LineItem *)CurrentItem;
            StartY=1;
            }
         else
            StartY--;
         TOS=FALSE;
         }
      else
         {
         CurrentItem=Start->PrevItem->NextItem=(struct LineItem *)
               End->NextItem;
         End->NextItem->PrevItem=
               (struct LineItem *)Start->PrevItem;
         }
   if(TOS)
      CurrentItem=FirstScrnItem=(struct LineItem *)End->NextItem;
   FreeListMem(Start,End);
   RemItem(CurrentItem);
   AddItem(CurrentItem);
   BackSearchRefresh(CurrentItem);
   PrintItemList(CurrentItem,StartY);
   PlotCursor(MinX(CurrentItem),StartY);
}

FreeListMem(Start,End)  /*Free several Items at once*/
struct LineItem *Start,*End;
{
   struct LineItem *Item,*Next;
   Next=(struct LineItem *)Start;
   do
      {
      Item=(struct LineItem *)Next;
      RemItem(Item);
      Next=(struct LineItem *)Item->NextItem;
      FreeMem(Item,sizeof(struct LineItem));
      }
   while(Item != End && Next != NULL);
}

DelTextBlock() /*Delete the highlighted text*/
{
   int c,Start,End,len;
   char Buffer[2];

   if(StartChar < EndChar)
      {
      Start=StartChar;
      End=EndChar;
      }
   else
      {
      Start=EndChar;
      End=StartChar;
      }
   len=strlen(InvItem->Text);

   for(c=0;c <= len-End; c++)
      InvItem->Text[c+Start]=InvItem->Text[c+End+1];

   PlotCursor(1,InvY);
   Buffer[0]=CSI;
   Buffer[1]=0x4b;
   WriteConsole(Buffer,2);
   PrintItem(InvItem);
   PlotCursor(MinX(InvItem)+Start,InvY);
   InvsMode=NOINV;
}

CancelInvs()  /*Cancel inversed text or lines*/
{
   if(NOINV == InvsMode)
      return(FALSE);
   else
      if(InvsMode > NOINV)
         EndLineInvs();
      else
         EndBlockInvs();

   return(TRUE);
}

DelInvs()   /*Delete the highlighted block or text*/
{
   if(InvsMode==NULL)
      return(FALSE);

   if(InvsMode > NOINV)
      DelTextBlock();
   else
      HandleDelBlock();

   return(TRUE);
}

TitleError(string)
char *string;
{
   DisplayBeep(Screen);
   ErrorInTitle = TRUE;
   SetWindowTitles(Window,-1,string);
}

TitleErrorCancel()
{
   static char Title[85];

   strcpy(Title,ScreenTitle);
   if(FileName[0])
      strncat(Title,FileName,65);
   else
      strcat(Title,"Untitled");
   if(Modified==TRUE)
      Title[0]='*';
   ErrorInTitle = FALSE;
   SetWindowTitles(Window,-1,Title);
}

BackSearchRefresh(Base)    /*Do a refresh of ItemNumbers by searching*/
struct LineItem *Base;    /*back through the item list*/
{
   struct LineItem *Work,Dummy;

   Dummy.PrevItem=(struct LineItem *)Base->PrevItem;
   Dummy.NextItem=(struct LineItem *)Base->NextItem;

   for(Dummy.Level=Base->Level;Dummy.Level > 0;Dummy.Level--)
      if((Work=(struct LineItem *)FindPrev(&Dummy))!=NULL)
         {
         RemItem(Work);
         AddItem(Work);
         }
}


