//
// The Fusion Library Interface for DOS
// Version 1.06c
// Copyright (C) 1990, 1991, 1992
// Software Dimensions
//
// DialogClass
//

#include "fli.h"

#ifdef __BCPLUSPLUS__
#pragma hdrstop
#endif

#include <bios.h>

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// UseDialog()
//
// Use the dialog
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

int DialogClass::UseDialog()
{
RestartHere:

  int KeyPress;
  DialogElement *Locator, *Magnet=0, *StoreMagnet;

  int ReturnElement;

  if (!(+Blaze))
    +Blaze;

  if (!First)
    return NoElement;

  if (!MultiTask || (MultiTask && !LocatedFirst))
  {
    Blaze.BigCursor();

    Present=First;

    do
    {
      if (Present->Available()==CompleteEvent)
        break;
      Present=Present->Next;
    }
    while (Present);

    if (!Present)
      return NoAvailableElement;
  }

  if (!BottomSave)
  {
    MouseHide();
    BottomSave=new char[Blaze.ComputeNeededBytes(Blaze.WhatWidth(),1)];
    Blaze.GetArea(0,Blaze.WhatHeight()-1,Blaze.WhatWidth(),1,BottomSave);
    MouseShow();
  }

  if (!MultiTask || (MultiTask && !LocatedFirst))
  {
    LocatedFirst=1;
    LastPresent=0;
    ShowElements();
    ShowHeading(0);
    FlushMouseQueue();
    Blaze.BigCursor();
  }

  for (;;)
  {

NewEvent:

    if (!Arrive(*Present))
      goto ExitGracefully;

    Blaze.VisibleCursor();

    HelpId=Present->FusionHelp;

    if (MultiTask || UseAction)
    {
      while(!(KeyPress=GetEvent(1)))
      {
        if (UseAction && biostime(0,0)>(ActionTimer+DialogTimer))
        {
          if (CallAllActions()==RefreshEvent)
            goto Refresh;
          ActionTimer=biostime(0,0);
        }

        if (MultiTask)
          return 0;
      }
    }
    else
      KeyPress=GetEvent();

    switch (KeyPress)
    {
      case MoveEvent:
        Blaze.Window(X+1,Y+1,Width-2,Height-2);
        Present->HighLight();
        Blaze.VisibleCursor();
        ShowLocator();
        Blaze.GetXY(XSave,YSave);
        continue;

      case HelpEvent:
        Blaze.GotoXY(XSave,YSave);
        Blaze.VisibleCursor();
        ShowLocator(1);
        continue;

      default:

        if (!NoDefaults)
        {
          if (KeyPress==kbTab)
          {
JumpNext:

            Magnet=0;

            if (!Valid())
              continue;

            if (!NextGroup())
              goto ExitGracefully;

            continue;
          }
          if (KeyPress==kbShiftTab)
          {
JumpLast:

            Magnet=0;

            if (!Valid())
              continue;

            if (!PreviousGroup())
              goto ExitGracefully;

            continue;
          }
        }

        Locator=First;

        if (KeyPress==MousedEvent)
        {
          if ((MouseEvent&MouseLeftButtonRelease ||
               MouseEvent&MouseLeftButtonPress)

               && MouseHorizontal>X
               && MouseHorizontal<X+Width-1
               && MouseVertical>Y
               && MouseVertical<Y+Height-1)
          {
            int ActualX;
            int ActualY;

            if (Y)
            {
              ActualX=MouseHorizontal-(X+1);
              ActualY=MouseVertical-(Y+1);
            }
            else
            {
              ActualX=MouseHorizontal-X;
              ActualY=MouseVertical-Y;
            }

            // --------------------------------------------------------------
            // Since a mouse button was released, see if the mouse is
            // currently touching an element.  If so, move to it if it is
            // available for access.
            // --------------------------------------------------------------

            StoreMagnet=Present;

            do
            {
              if (ActualX>=Locator->X
                && ActualX<Locator->X+Locator->Width
                && ActualY>=Locator->Y
                && ActualY<Locator->Y+Locator->Height
                && Locator->Available()!=FailedEvent
                && Locator!=Present)
              {
                if (!Valid())
                  goto NewEvent;

                MouseHide();

                if (!Depart(*Present))
                  goto ExitGracefully;

                Present=Locator;

                if (!Arrive(*Present))
                  goto ExitGracefully;

                MouseHorizontal=ActualX;
                MouseVertical=ActualY;
                MouseShow();

                KeyPress=ValidatedMousedEvent;
                Magnet=StoreMagnet;

                goto ProcessEvent;
              }
              Locator=Locator->Next;
            }
            while (Locator);

            goto PassMouseEventFurther;
          }
          else
          {

PassMouseEventFurther:

            if (Y)
            {
              MouseHorizontal-=(X+1);
              MouseVertical-=(Y+1);
            }
            else
            {
              MouseHorizontal-=X;
              MouseVertical-=Y;
            }


            if (MouseHorizontal>=Present->X
              && MouseHorizontal<Present->X+Present->Width
              && MouseVertical>=Present->Y
              && MouseVertical<Present->Y+Present->Height)
                KeyPress=ValidatedMousedEvent;

            goto ProcessEvent;
          }
        }

        // --------------------------------------------------------------
        // Scan through available groups and search for a particular
        // "Hot" key pattern.  Once found, jump to it.  If the key is not
        // a "Hot" key for one of the groups -- pass the key along to
        // the event handler stream (element event -> dialog event)
        // --------------------------------------------------------------

        if (HeadingCount)
        {
          for (int i=0;i<HeadingCount;i++)
            if ((HeadingStorage+i)->HotKey==KeyPress &&
              Present->GroupCode!=(HeadingStorage+i)->GroupCode)
            {
              int j=(HeadingStorage+i)->GroupCode;

              DialogElement *Pres=Present;
              DialogElement *Present=First;

              do
              {
                if (Present->GroupCode==j &&
                  Present->Available()==CompleteEvent)
                {
                  if (!Valid())
                    goto NewEvent;

                  if (!Depart(*Pres))
                    goto ExitGracefully;

                  DialogClass::Present=Present;

                  if (!Arrive(*Present))
                    goto ExitGracefully;

                  goto NewEvent;
                }
                Present=Present->Next;
                LastPresent=0;
              }
              while (Present);
            }
        }

        // --------------------------------------------------------------
        // Scan through available elements and search for a particular
        // "Hot" key pattern.  Once found, jump to it.  If the key is not
        // a "Hot" key for one of the elements -- pass the key along to
        // the event handler stream (element event -> dialog event)
        // --------------------------------------------------------------

        Locator=First;
        StoreMagnet=Present;

        do
        {
          if (Locator!=Present
              && (Locator->QuickKey==KeyPress ||
              (KeyPress>='a' && KeyPress<='z' &&
              Locator->QuickKey==(KeyPress-32)))
              && Locator->Available()!=FailedEvent)
          {
            if (!Valid())
              goto NewEvent;

            if (!Depart(*Present))
              goto ExitGracefully;

            Present=Locator;

            if (!Arrive(*Present))
              goto ExitGracefully;

            LastPresent=0;

            Magnet=StoreMagnet;

            goto ProcessEvent;
          }
          Locator=Locator->Next;
        }
        while (Locator);

        // --------------------------------------------------------------
        // Pass key or mouse event along to element event handler for
        // processing.  If the element event handler doesn't use it, it
        // will be passed to the dialog (global) event handler for
        // processing and final distribution.
        // --------------------------------------------------------------

ProcessEvent:

        switch (ReturnElement=Present->EventHandler(KeyPress))
        {
          case StopEvent:
            if (!Valid())
              continue;
          case AbortEvent:
            MouseHide();
            if (BottomSave)
            {
              Blaze.PutArea(0,Blaze.WhatHeight()-1,BottomSave);
              delete BottomSave;
              BottomSave=0;
            }
            MouseShow();
            AlreadyShown=0;
            Blaze.BigCursor();
            return KeyPress;

          case FullValidationEvent:

            {
              DialogElement *FullCheck=First;

              do
              {
                if (FullCheck->Available()==CompleteEvent &&
                  FullCheck->Validation()==FailedEvent)
                {
                  if (!Depart(*Present))
                    goto ExitGracefully;

                  Present=FullCheck;

                  if (!Arrive(*Present))
                    goto ExitGracefully;

                  LastPresent=0;
                  Magnet=0;

                  EventHandler(FullValidationEvent);

                  goto NewEvent;
                }
                FullCheck=FullCheck->Next;
              }
              while (FullCheck);

              MouseHide();
              if (BottomSave)
              {
                Blaze.PutArea(0,Blaze.WhatHeight()-1,BottomSave);
                delete BottomSave;
                BottomSave=0;
              }
              MouseShow();
              AlreadyShown=0;
              Blaze.BigCursor();
              return KeyPress;
            }

          case RestartEvent:
            LastPresent=0;
            goto RestartHere;

          case CompleteEvent:
            Magnet=0;
            if (Present->Available()==FailedEvent)
              goto JumpNext;
            continue;

          case RefreshEvent:

Refresh:

            Magnet=0;
            LastPresent=0;
            AlreadyShown=0;
            ShowElements();
            if (Present->Available()==FailedEvent)
              goto JumpNext;
            Present->HighLight();
            continue;

          case OtherRefreshEvent:

OtherRefresh:

            Magnet=0;
            LastPresent=0;
            AlreadyShown=0;
            ShowElements(1);
            if (Present->Available()==FailedEvent)
              goto JumpNext;
            Present->HighLight();
            continue;

          case NextElementEvent:
            Magnet=0;
            if (!Valid())
              continue;
            if (!NextElement())
              goto ExitGracefully;
            continue;

          case PreviousElementEvent:
            Magnet=0;
            if (!Valid())
              continue;
            if (!PreviousElement())
              goto ExitGracefully;
            continue;

          case NextGroupEvent:
            Magnet=0;
            if (!Valid())
              continue;
            if (!NextGroup())
              goto ExitGracefully;
            continue;

          case PreviousGroupEvent:
            Magnet=0;
            if (!Valid())
              continue;
            if (!PreviousGroup())
              goto ExitGracefully;
            continue;

          case NextWithinGroupEvent:
            Magnet=0;
            if (!Valid())
              continue;
            if (!NextWithinGroup())
              goto ExitGracefully;
            continue;

          case PreviousWithinGroupEvent:
            Magnet=0;
            if (!Valid())
              continue;
            if (!PreviousWithinGroup())
              goto ExitGracefully;
            continue;

          case RefreshMagnetEvent:
          case OtherRefreshMagnetEvent:
          case MagnetEvent:
            if (Magnet && Magnet->Available()==CompleteEvent && Valid())
            {
              if (!Depart(*Present))
                goto ExitGracefully;
              Present=Magnet;
              if (!Arrive(*Present))
                goto ExitGracefully;
              Magnet=0;
            }
            Magnet=0;
            if (ReturnElement==RefreshMagnetEvent)
              goto Refresh;
            if (ReturnElement==OtherRefreshMagnetEvent)
              goto OtherRefresh;

            continue;

          // --------------------------------------------------------------
          // Check for existance of groupings -- if so, jump to a new
          // element within the current group
          // --------------------------------------------------------------

          default:

            if (Grouped && Grouped>1 && Present->GroupCode &&
              (KeyPress==kbDown || KeyPress==kbUp) && !NoDefaults)
            {
              if (KeyPress==kbDown)
              {
                Magnet=0;

                if (!Valid())
                  continue;

                if (!NextWithinGroup())
                  goto ExitGracefully;

                continue;
              }
              else
              {
                Magnet=0;

                if (!Valid())
                  continue;

                if (!PreviousWithinGroup())
                  goto ExitGracefully;

                continue;
              }
            }

            // --------------------------------------------------------------
            // Pass the key or mouse event along to the dialog (global) event
            // handler.  If it isn't used during this pass, the event is
            // thrown out and assumed to be a "dead" (unused) event.
            // --------------------------------------------------------------

            Blaze.GetXY(XSave,YSave);

            int PullBack;

            switch (PullBack=EventHandler(ReturnElement))
            {
              case StopEvent:
                if (!Valid())
                  continue;
              case AbortEvent:
                Blaze.InvisibleCursor();
                MouseHide();
                if (BottomSave)
                {
                  Blaze.PutArea(0,Blaze.WhatHeight()-1,BottomSave);
                  delete BottomSave;
                  BottomSave=0;
                }
                MouseShow();
                AlreadyShown=0;
                Blaze.BigCursor();
                return ReturnElement;

              case FullValidationEvent:

                {
                  DialogElement *FullCheck=First;

                  do
                  {
                    if (FullCheck->Available()==CompleteEvent &&
                      FullCheck->Validation()==FailedEvent)
                    {
                      if (!Depart(*Present))
                        goto ExitGracefully;

                      Present=FullCheck;

                      if (!Arrive(*Present))
                        goto ExitGracefully;

                      LastPresent=0;
                      Magnet=0;

                      EventHandler(FullValidationEvent);

                      goto NewEvent;
                    }
                    FullCheck=FullCheck->Next;
                  }
                  while (FullCheck);

                  MouseHide();
                  if (BottomSave)
                  {
                    Blaze.PutArea(0,Blaze.WhatHeight()-1,BottomSave);
                    delete BottomSave;
                    BottomSave=0;
                  }
                  MouseShow();
                  AlreadyShown=0;
                  Blaze.BigCursor();
                  return KeyPress;
                }

              case RefreshEvent:

GlobalRefresh:

                Blaze.GotoXY(XSave,YSave);
                Magnet=0;
                LastPresent=0;
                AlreadyShown=0;
                ShowElements();
                if (Present->Available()==FailedEvent)
                  goto JumpNext;
                Present->HighLight();
                continue;

              case OtherRefreshEvent:

GlobalOtherRefresh:

                Blaze.GotoXY(XSave,YSave);
                Magnet=0;
                LastPresent=0;
                AlreadyShown=0;
                ShowElements(1);
                if (Present->Available()==FailedEvent)
                  goto JumpNext;
                Present->HighLight();
                continue;

              case RestartEvent:
                LastPresent=0;
                goto RestartHere;

              case NextElementEvent:
                Magnet=0;
                if (!Valid())
                  continue;
                if (!NextElement())
                  goto ExitGracefully;
                continue;

              case PreviousElementEvent:
                Magnet=0;
                if (!Valid())
                  continue;
                if (!PreviousElement())
                  goto ExitGracefully;
                continue;

              case NextGroupEvent:
                Magnet=0;
                if (!Valid())
                  continue;
                if (!NextGroup())
                  goto ExitGracefully;
                continue;

              case PreviousGroupEvent:
                Magnet=0;
                if (!Valid())
                  continue;
                if (!PreviousGroup())
                  goto ExitGracefully;
                continue;

              case NextWithinGroupEvent:
                Magnet=0;
                if (!Valid())
                  continue;
                if (!NextWithinGroup())
                  goto ExitGracefully;
                continue;

              case PreviousWithinGroupEvent:
                Magnet=0;
                if (!Valid())
                  continue;
                if (!PreviousWithinGroup())
                  goto ExitGracefully;
                continue;

              case RefreshMagnetEvent:
              case OtherRefreshMagnetEvent:
              case MagnetEvent:
                if (Magnet && Magnet->Available()==CompleteEvent && Valid())
                {
                  if (!Depart(*Present))
                    goto ExitGracefully;
                  Present=Magnet;
                  if (!Arrive(*Present))
                    goto ExitGracefully;
                  Magnet=0;
                }
                Magnet=0;
                if (PullBack==RefreshMagnetEvent)
                  goto GlobalRefresh;
                if (PullBack==OtherRefreshMagnetEvent)
                  goto GlobalOtherRefresh;

                continue;

              case CompleteEvent:
              default:
                Blaze.GotoXY(XSave,YSave);
                Blaze.VisibleCursor();
                if (Present->Available()==FailedEvent)
                  goto JumpNext;
                continue;
            }
        }
    }
  }

ExitGracefully:

  MouseHide();

  if (BottomSave)
  {
    Blaze.PutArea(0,Blaze.WhatHeight()-1,BottomSave);
    delete BottomSave;
    BottomSave=0;
  }

  MouseShow();

  Blaze.InvisibleCursor();
  Blaze.BigCursor();

  return StopEvent;

}
