/*
 *  CELLS       An Implementation of the WireWorld cellular automata
 *              as described in Scientific American, Jan 1990.
 *
 *              Copyright 1990 by Davide P. Cervone.
 *  You may use this code, provided this copyright notice is kept intact.
 *  See the CELLS.HELP file for complete information on distribution conditions.
 */

/*
 *  File:  cSlider.c            Handles the main grid sliders and zoom gadgets.
 */


#include "cGadget.h"
 

/*
 *  UpdateSliders()
 *
 *  Find the new pot and body values for the sliders and update the slider's
 *  gadgets if necessary.
 */

void UpdateSliders()
{
   int Pot,Body;

   Body = 0xFFFF * GridW / MAXGRIDW;
   if (GridW != MAXGRIDW)
      Pot = 0xFFFF * GridX / (MAXGRIDW - GridW);
     else
      Pot = 0;
   if (Body != cSlider[PROP_SLIDEH].HorizBody ||
       Pot  != cSlider[PROP_SLIDEH].HorizPot)
          NewModifyProp(&cGadget[ID_SLIDEH],myWindow,NULL,
             cSlider[PROP_SLIDEH].Flags,Pot,0,Body,0,1);

   Body = 0xFFFF * GridH / MAXGRIDH;
   if (GridH != MAXGRIDH)
      Pot = 0xFFFF * GridY / (MAXGRIDH - GridH);
     else
      Pot = 0;
   if (Body != cSlider[PROP_SLIDEV].VertBody ||
       Pot  != cSlider[PROP_SLIDEV].VertPot)
          NewModifyProp(&cGadget[ID_SLIDEV],myWindow,NULL,
             cSlider[PROP_SLIDEV].Flags,0,Pot,0,Body,1);
}


/*
 *  DoSlideH()
 *
 *  Find the new grid position determined by the horizontal slider, and
 *  If it is different from the existing position, then
 *    If the existing position does not overlap the new position, 
 *      clear the screen abd refresh it completely,
 *    Otherwise
 *      calculate the offsets from the current position
 *      and scroll the grid the desired amount.
 *      Clear the newly uncovered area, and refresh it
 *      then update the screen from the double buffer
 */

void DoSlideH()
{
   short x,dx;
   
   x = ((MAXGRIDW - GridW) * cSlider[PROP_SLIDEH].HorizPot + 0x7FFF) / 0xFFFF;
   if (x >= MAXGRIDW) x = MAXGRIDW - 1;

   if (x != GridX)
   {
      if (x + GridW <= GridX || x >= GridX + GridW)
      {
         GridX = x;
         ClearScreen(FALSE);
         RefreshScreen(CurGen);
      } else {
         dx = GridX - x; GridX = x; x = 0;
         ScrollScreen(-dx,0);
         if (dx < 0) {x = dx + GridW; dx = -dx;}
         ClearPatch(x,0,dx,GridH);
         RefreshPatch(x,0,dx,GridH,CurGen);
         UpdateScreen();
      }
   }
}


/*
 *  DoSlideV()
 *
 *  Find the new grid position determined by the vertical slider, and
 *  If it is different from the existing position, then
 *    If the existing position does not overlap the new position, 
 *      clear the screen abd refresh it completely,
 *    Otherwise
 *      calculate the offsets from the current position
 *      and scroll the grid the desired amount.
 *      Clear the newly uncovered area, and refresh it
 *      then update the screen from the double buffer
 */

void DoSlideV()
{
   short y,dy;
   
   y = ((MAXGRIDH - GridH) * cSlider[PROP_SLIDEV].VertPot + 0x7FFF) / 0xFFFF;
   if (y >= MAXGRIDH) y = MAXGRIDH - 1;

   if (y != GridY)
   {
      if (y + GridH <= GridY || y >= GridY + GridH)
      {
         GridY = y;
         ClearScreen(FALSE);
         RefreshScreen(CurGen);
      } else {
         dy = GridY - y; GridY = y; y = 0;
         ScrollScreen(0,-dy);
         if (dy < 0) {y = dy + GridH; dy = -dy;}
         ClearPatch(0,y,GridW,dy);
         RefreshPatch(0,y,GridW,dy,CurGen);
         UpdateScreen();
      }
   }
}


/*
 *  DoScrollLeft()
 *
 *  While there's still more room to scroll and the arrow is selected,
 *    update the current position and scroll the screen by one cell
 *    clear the uncovered patch and refresh it, then update the screen
 *    from the double buffer.  Update the sliders to reflect the new
 *    grid position.
 */

void DoScrollLeft(theGadget)
struct Gadget *theGadget;
{
   while (GridX > 0 && (theGadget->Flags & SELECTED))
   {
      GridX--; ScrollScreen(-1,0);
      ClearPatch(0,0,1,GridH);
      RefreshPatch(0,0,1,GridH,CurGen);
      UpdateScreen();
      UpdateSliders();
   }
}


/*
 *  DoScrollRight()
 *
 *  While there's still more room to scroll and the arrow is selected,
 *    update the current position and scroll the screen by one cell
 *    clear the uncovered patch and refresh it, then update the screen
 *    from the double buffer.  Update the sliders to reflect the new
 *    grid position.
 */

void DoScrollRight(theGadget)
struct Gadget *theGadget;
{
   while (GridX < MAXGRIDW-GridW && (theGadget->Flags & SELECTED))
   {
      GridX++; ScrollScreen(1,0);
      ClearPatch(GridW-1,0,1,GridH);
      RefreshPatch(GridW-1,0,1,GridH,CurGen);
      UpdateScreen();
      UpdateSliders();
   }
}


/*
 *  DoScrollUp()
 *
 *  While there's still more room to scroll and the arrow is selected,
 *    update the current position and scroll the screen by one cell
 *    clear the uncovered patch and refresh it, then update the screen
 *    from the double buffer.  Update the sliders to reflect the new
 *    grid position.
 */

void DoScrollUp(theGadget)
struct Gadget *theGadget;
{
   while (GridY > 0 && (theGadget->Flags & SELECTED))
   {
      GridY--; ScrollScreen(0,-1);
      ClearPatch(0,0,GridW,1);
      RefreshPatch(0,0,GridW,1,CurGen);
      UpdateScreen();
      UpdateSliders();
   }
}


/*
 *  DoScrollDown()
 *
 *  While there's still more room to scroll and the arrow is selected,
 *    update the current position and scroll the screen by one cell
 *    clear the uncovered patch and refresh it, then update the screen
 *    from the double buffer.  Update the sliders to reflect the new
 *    grid position.
 */

void DoScrollDown(theGadget)
struct Gadget *theGadget;
{
   while (GridY < MAXGRIDH-GridH && (theGadget->Flags & SELECTED))
   {
      GridY++; ScrollScreen(0,1);
      ClearPatch(0,GridH-1,GridW,1);
      RefreshPatch(0,GridH-1,GridW,1,CurGen);
      UpdateScreen();
      UpdateSliders();
   }
}


/*
 *  DoZoom()
 *
 *  If the cellsize can still be increased,
 *    Set the board variables to the new size,
 *    Clear the screen and refresh it in the new size.
 *    Update the sliders to their new positions and sizes.
 */

void DoZoom()
{
   if (CellSize < MAXCELLSIZE)
   {
      SetBoardSize(CellSize+1);
      ClearScreen(FALSE);
      RefreshScreen(CurGen);
      UpdateSliders();
   }
}


/*
 *  DoShrink()
 *
 *  If the cell size can still get smaller,
 *    Set the board variables to the new size,
 *    Clear the screen and refresh it in the new size.
 *    Update the sliders to their new positions and sizes.
 */

void DoShrink()
{
   if (CellSize > MINCELLSIZE)
   {
      SetBoardSize(CellSize-1);
      ClearScreen(FALSE);
      RefreshScreen(CurGen);
      UpdateSliders();
   }
}
