/**************************************************************************
 *  File name  :  img_size.c
 *
 *  Description:  This module contains the code for sizing the main window,
 *                and scrolling the image inside the window.
 *                Functions contained here:
 *
 *                SizeMainWindow()
 *                SizeCalculateMaxWindow(prclBound)
 *                SizePositionImage(mp2)
 *                SizeVScroll(mp2, rcl, ptl)
 *                SizeHScroll(mp2, rcl, ptl)
 *                ScrollBars(usWidth, usHeight)
 *                Scroll(lThmbpos, lDeltaSc, sScrollType, prclInvalid)
 *
 *  Concepts   :  sizable windows
 *
 *  API's      :  WinSetWindowPos
 *                WinQueryWindowRect
 *                GpiSetCurrentPosition
 *                WinSendMsg
 *                WinWindowFromID
 *                WinScrollWindow
 *                WinInvalidateRect
 *                GpiQueryCurrentPosition
 *
 *  Required
 *    Files    :  OS2.H, STRING.H, STDLIB.H, IMG_MAIN.H, IMG_XTRN.H
 *
 *  Copyright (C) 1991 IBM Corporation
 *
 *      DISCLAIMER OF WARRANTIES.  The following [enclosed] code is
 *      sample code created by IBM Corporation. This sample code is not
 *      part of any standard or IBM product and is provided to you solely
 *      for  the purpose of assisting you in the development of your
 *      applications.  The code is provided "AS IS", without
 *      warranty of any kind.  IBM shall not be liable for any damages
 *      arising out of your use of the sample code, even if they have been
 *      advised of the possibility of such damages.                                                    *
 *************************************************************************/
/*
 *  Include files, macros, defined constants, and externs
 */
#define INCL_WINSCROLLBARS
#define INCL_WINFRAMEMGR
#define INCL_WINSTDFILE
#define INCL_GPIPRIMITIVES

#include <os2.h>
#include <string.h>
#include <stdlib.h>

#include "img_main.h"
#include "img_xtrn.h"

/*
 *  Static variables
 */
ULONG ulScrollXPage;
ULONG ulScrollYPage;
ULONG ulScrollYLine  = LINESCROLL;
ULONG ulScrollXLine  = LINESCROLL;

/*
 *  Entry point declarations
 */
VOID ScrollBars(USHORT usWidth, USHORT usHeight);
VOID Scroll(LONG lThmbpos, LONG lDeltaSc, SHORT sScrollType,
            PRECTL prclInvalid);

/**************************************************************************
 *
 *  Name       : SizeMainWindow()
 *
 *  Description: Maximizes the amount of the image that is
 *               visible . This can only be done after the image
 *               has been loaded, as the size of the window is
 *               directly related to the size of the image.
 *
 *  Concepts   : Routine is called whenever a WM_COMMAND message
 *               is posted to the main window as a result of
 *               selecting the 'Detail' item on the 'View'
 *               pulldown.
 *
 *                Sets the size and position of the main window
 *                whenever 'Detail' mode is selected.
 *
 *  API's      :  WinSetWindowPos
 *                WinQueryWindowRect
 *                GpiSetCurrentPosition
 *
 *  Parameters :  [none]
 *
 *  Return     :  [none]
 *
 *************************************************************************/
VOID SizeMainWindow(void)
{
    RECTL  rcl, rclCWM;

    /* limit the window size */
    SizeCalculateMaxWindow(&rclCWM);
    WinSetWindowPos(vhwndFrame, (HWND)NULL,
                    (SHORT)rclCWM.xLeft,
                    (SHORT)rclCWM.yBottom,
                    (SHORT)(rclCWM.xRight - rclCWM.xLeft),
                    (SHORT)(rclCWM.yTop - rclCWM.yBottom),
                    SWP_MOVE | SWP_SIZE);

   /*
    * The position of the top-left corner of the window rectangle is
    * recorded and selected as the current position before the image is
    * drawn.
    */

    WinQueryWindowRect(vhwndClient, &rcl);
    vptlSave.x = rcl.xLeft;
    vptlSave.y = rcl.yTop;
    GpiSetCurrentPosition(vhps, &vptlSave);

   /*
    * set the scroll-bar range and slider position and size
    */
    ScrollBars((USHORT)(rcl.xRight - rcl.xLeft),
               (USHORT)(rcl.yTop - rcl.yBottom));

}   /* End of SizeMainWindow */

/**************************************************************************
 *
 *  Name       : Scroll()
 *
 *  Description: Scrolls the window contents horizontally or
 *               vertically.
 *
 *  Concepts   : Routine is called from SizeVScroll() and
 *               SizeHScroll()
 *               - reposition slider
 *               - scroll the window contents in the required
 *                 direction by the required amount.
 *
 *  API's      :  WinSendMsg
 *                WinWindowFromID
 *                WinScrollWindow
 *
 *  Parameters :  lThmbPos =  new thumb position
 *                lDeltaSc =  scrolled amount
 *                sScrollType =  horizontal/vertical scroll ?
 *                prclInvalid) = invalidated area
 *
 *  Return     :  [none]
 *
 *************************************************************************/
VOID Scroll(
            LONG   lThmbPos,        /* new thumb position */
            LONG   lDeltaSc,        /* scrolled amount */
            SHORT  sScrollType,     /* horizontal/vertical scroll ? */
            PRECTL prclInvalid)     /* invalidated area */
{
   unsigned Fid;

   /* determine type of scroll operation */
   Fid = sScrollType == VERTSCROLL ? FID_VERTSCROLL : FID_HORZSCROLL;

  /*
   * reposition the slider
   */
   WinSendMsg(WinWindowFromID(vhwndFrame, Fid),
              SBM_SETPOS,
              MPFROMLONG(lThmbPos),
              (MPARAM)NULL);

  /*
   * scroll the window contents
   */

   if (sScrollType == VERTSCROLL)

       /* vertical scroll */
       WinScrollWindow(vhwndClient,
                       0,
                       (SHORT)lDeltaSc,
                       (PRECTL)NULL,
                       (PRECTL)NULL,
                       (HRGN)NULL,
                       (PRECTL)prclInvalid,
                       0);
   else

       /* horizontal scroll */
       WinScrollWindow(vhwndClient,
                       (SHORT)lDeltaSc,
                       0,
                       (PRECTL)NULL,
                       (PRECTL)NULL,
                       (HRGN)NULL,
                       (PRECTL)prclInvalid,
                       0);

}   /* End of Scroll */


/**************************************************************************
 *
 *  Name       : ScrollBars()
 *
 *  Description: Prepares the main window for scrolling (i.e.
 *               set up the scrollbars appropriately)
 *
 *  Concepts   : Routine is called from WndSize() and SizeMain()
 *               - set scrollbar ranges
 *               - set slider size relative to the current window
 *                 size
 *
 *  API's      :  WinSendMsg
 *                GpiQueryCurrentPosition
 *
 *  Parameters :  usWidth  =  width
 *                usHeight =  height
 *
 *  Return     :  [none]
 *
 *************************************************************************/
VOID ScrollBars(USHORT usWidth, USHORT usHeight)
{
   POINTL ptlCur;

  /*
   * calculate the full scrolling range
   */
   vulScrollXMax = vsizlImg.cx - usWidth;
   vulScrollYMax = vsizlImg.cy - usHeight;

  /*
   * The page-scrolling action scrolls the image by half of the window
   * extent in both axes.
   */
   ulScrollXPage = usWidth  / 2;
   ulScrollYPage = usHeight / 2;

  /*
   * get current position, which is at the top-left of the image
   */
   GpiQueryCurrentPosition(vhps, &ptlCur);

  /*
   * The scroll-bar slider is positioned according to the position
   * of the image in the newly-sized window.
   */
   WinSendMsg(vhwndHScroll,
              SBM_SETSCROLLBAR,
              MPFROMLONG(-ptlCur.x),                  /* slider position */
              MPFROM2SHORT(0, (SHORT)vulScrollXMax));   /* range         */

   WinSendMsg(vhwndVScroll,
              SBM_SETSCROLLBAR,
              MPFROMLONG(ptlCur.y - usHeight),        /* slider position */
              MPFROM2SHORT(0, (SHORT)vulScrollYMax));   /* range         */

   WinSendMsg(vhwndHScroll,
              SBM_SETTHUMBSIZE,
              MPFROM2SHORT(usWidth, (SHORT)(vsizlImg.cx)),
              (MPARAM)0L);

   WinSendMsg(vhwndVScroll,
              SBM_SETTHUMBSIZE,
              MPFROM2SHORT(usHeight, (SHORT)(vsizlImg.cy)),
              (MPARAM)0L);

}  /* End of ScrollBars */

/**************************************************************************
 *
 *  Name       : SizeCalculateMaxWindow()
 *
 *  Description: Calculates the maximized window size, which
 *               must not exceed the size of the loaded image.
 *
 *  Concepts   : Routine is called from SizeMain(), LoadImage(),
 *               MainWndProc() and FrameWndProc()
 *
 *               max_window_size = min(screen_size, image_size)
 *
 *  API's      :  [none]
 *
 *  Parameters :  prclBound = points to the bounding rectangle
 *
 *  Return     :   TRUE  - if image loaded and in 'Detail' mode
 *                 FALSE - if either the image isn't loaded or
 *                       the application is not in 'Detail' mode
 *
 *************************************************************************/
BOOL SizeCalculateMaxWindow(prclBound)
PRECTL prclBound;
{
  /*
   * Calculate the maximized window size. If an image has been loaded
   * in 'Detail' mode, the maximized window is the smaller of the
   * screen and the image.
   */

   if (vfImgLoaded && vfDetail)
   {
       if (vsizlImg.cx > (vlYScreen - vlcxVScroll))
       {
           prclBound->xLeft  = -vlcxBorder;
           prclBound->xRight = prclBound->xLeft + vlYScreen +
                               (2*vlcxBorder);
       }
       else
       {
           prclBound->xLeft  = 0;
           prclBound->xRight = prclBound->xLeft +
                               vsizlImg.cx + vlcxVScroll +
                               (2*vlcxBorder);
       }

       if (vsizlImg.cy >
           (vlYScreen - vlcyHScroll - vlcyMenu - vlcyTitle))
       {
           prclBound->yBottom = -vlcyBorder;
           prclBound->yTop = prclBound->yBottom + vlYScreen +
                             (2*vlcyBorder);
       }
       else
       {
           prclBound->yTop = vlYScreen;
           prclBound->yBottom = prclBound->yTop -
                                (vsizlImg.cy + vlcyTitle + vlcyMenu +
                                 vlcyHScroll + (2*vlcyBorder));
       }
       return  TRUE;
   }
   else
       /* error if not in 'Detail' mode */
       return FALSE;
}   /* End of SizeCalculateMaxWindow */

/**************************************************************************
 *
 *  Name       : SizeVScroll(mp2, rcl, ptl)
 *
 *  Description: Implements vertical scrolling in 'Detail' mode
 *
 *  Concepts   : Routine is called MainWndProc() and it invokes
 *               Scroll().
 *
 *               -adjust current position
 *               -redraw image at new position
 *
 *  API's      : GpiSetCurrentPosition
 *               WinInvalidateRect
 *
 *  Parameters :  mp2 = second message parameter
 *                rcl = rectangle
 *                ptl = new position
 *
 *  Return     :  [none]
 *
 *************************************************************************/
VOID SizeVScroll(MPARAM mp2, RECTL rcl, POINTL ptl)
{
   LONG   lDeltaScr;

   /* act on the type of vertical scroll message */
   switch (SHORT2FROMMP(mp2))
   {
       case SB_LINEDOWN:

          /*
           * line-down processing
           */
           if ((ULONG)(ptl.y - rcl.yTop) < vulScrollYMax)
           {
               lDeltaScr = ptl.y;
               ptl.y +=
                   ((ULONG)(ptl.y - rcl.yTop) + ulScrollYLine < vulScrollYMax) ?
                   ulScrollYLine : vulScrollYMax - (ptl.y - rcl.yTop);
               lDeltaScr = ptl.y - lDeltaScr;
               GpiSetCurrentPosition(vhps, &ptl);
               Scroll((ptl.y-rcl.yTop), lDeltaScr, VERTSCROLL, &rcl);
               WinInvalidateRect(vhwndClient, &rcl, FALSE);
           }
           break;

       case SB_LINEUP:

          /*
           * line-up processing
           */
           if (ptl.y > rcl.yTop)
           {
               lDeltaScr = ptl.y;
               ptl.y -= (ptl.y > rcl.yTop + ulScrollYLine) ?
                         ulScrollYLine : ptl.y - rcl.yTop;
               lDeltaScr = ptl.y - lDeltaScr;
               GpiSetCurrentPosition(vhps, &ptl);
               Scroll((ptl.y-rcl.yTop), lDeltaScr, VERTSCROLL, &rcl);
               WinInvalidateRect(vhwndClient, &rcl, FALSE);
           }
           break;

       case SB_PAGEDOWN:

          /*
           * page-down processing
           */
           if ((ULONG)(ptl.y - rcl.yTop) < vulScrollYMax)
           {
               lDeltaScr =
                   ((ULONG)(ptl.y - rcl.yTop) + ulScrollYPage < vulScrollYMax) ?
                    ulScrollYPage : vulScrollYMax -
                    (SHORT)(ptl.y - rcl.yTop);
               ptl.y += lDeltaScr;
               GpiSetCurrentPosition(vhps, &ptl);
               Scroll((ptl.y-rcl.yTop), lDeltaScr, VERTSCROLL, &rcl);
               WinInvalidateRect(vhwndClient, &rcl, FALSE);
           }
           break;

       case SB_PAGEUP:

          /*
           * page-up processing
           */
           if (ptl.y > rcl.yTop)
           {
               lDeltaScr = (ptl.y > rcl.yTop + ulScrollYPage) ?
                            ulScrollYPage : (SHORT)(ptl.y - rcl.yTop);
               ptl.y -= lDeltaScr;
               GpiSetCurrentPosition(vhps, &ptl);
               Scroll((ptl.y-rcl.yTop), -lDeltaScr, VERTSCROLL, &rcl);
               WinInvalidateRect(vhwndClient, &rcl, FALSE);
           }
           break;

       case SB_SLIDERPOSITION:

          /*
           * adjust the slider position
           */
           lDeltaScr = ptl.y;
           ptl.y = rcl.yTop + SHORT1FROMMP(mp2);
           lDeltaScr = ptl.y - lDeltaScr;
           GpiSetCurrentPosition(vhps, &ptl);
           Scroll((LONG)(SHORT1FROMMP(mp2)), lDeltaScr, VERTSCROLL, &rcl);
           WinInvalidateRect(vhwndClient, &rcl, FALSE);
           break;

   }
}   /* End of SizeVScroll() */

/**************************************************************************
 *
 *  Name       : SizeHScroll(mp2, rcl, ptl)
 *
 *  Description: Implements horizontal scrolling in 'Detail' mode
 *
 *  Concepts   : Routine is called MainWndProc() and it invokes
 *               Scroll().
 *
 *               -adjust current position
 *               -redraw image at new position
 *
 *  API's      : GpiSetCurrentPosition
 *               WinInvalidateRect
 *
 *  Parameters :  mp2 = second message parameter
 *                rcl = rectangle
 *                ptl = new position
 *
 *  Return     :  [none]
 *
 *************************************************************************/
VOID SizeHScroll(MPARAM mp2, RECTL rcl, POINTL ptl)
{
   LONG   lDeltaScr;

   /* act on the type of horizontal scroll message */
   switch(SHORT2FROMMP(mp2))
   {
       case SB_LINERIGHT:

          /*
           * line-right processing
           */
           if ((vsizlImg.cx + ptl.x) > rcl.xRight)
           {
               lDeltaScr = ptl.x;
               ptl.x -=
                   ((vsizlImg.cx + ptl.x) > rcl.xRight+ulScrollXLine) ?
                   ulScrollXLine : ptl.x + vsizlImg.cx - rcl.xRight;
               lDeltaScr = ptl.x - lDeltaScr;
               GpiSetCurrentPosition(vhps, &ptl);
               Scroll(-ptl.x, lDeltaScr, HORZSCROLL, &rcl);
               WinInvalidateRect(vhwndClient, &rcl, FALSE);
           }
           break;

       case SB_LINELEFT:

          /*
           * line-left processing
           */
           if (ptl.x < rcl.xLeft)
           {
               lDeltaScr = ptl.x;
               ptl.x += ((ULONG)(rcl.xLeft - ptl.x) > ulScrollXLine) ?
                         ulScrollXLine : rcl.xLeft - ptl.x;
               lDeltaScr = ptl.x - lDeltaScr;
               GpiSetCurrentPosition(vhps, &ptl);
               Scroll(-ptl.x, lDeltaScr, HORZSCROLL, &rcl);
               WinInvalidateRect(vhwndClient, &rcl, FALSE);
           }
           break;

       case SB_PAGERIGHT:

          /*
           * page-right processing
           */
           if ((vsizlImg.cx + ptl.x) > rcl.xRight)
           {
               lDeltaScr =
                  ((vsizlImg.cx+(LONG)ptl.x) > rcl.xRight+ulScrollXPage) ?
                  ulScrollXPage : (vsizlImg.cx + ptl.x - rcl.xRight);
               ptl.x -= (LONG)lDeltaScr;
               GpiSetCurrentPosition(vhps, &ptl);
               Scroll(-ptl.x, -lDeltaScr, HORZSCROLL, &rcl);
               WinInvalidateRect(vhwndClient, &rcl, FALSE);
           }
           break;

       case SB_PAGELEFT:

          /*
           * page-left processing
           */
           if (ptl.x < rcl.xLeft)
           {
               lDeltaScr = ((ULONG)(rcl.xLeft - ptl.x) > ulScrollXPage) ?
                            ulScrollXPage : (SHORT)(rcl.xLeft - ptl.x);
               ptl.x += lDeltaScr;
               GpiSetCurrentPosition(vhps, &ptl);
               Scroll(-ptl.x, lDeltaScr, HORZSCROLL, &rcl);
               WinInvalidateRect(vhwndClient, &rcl, FALSE);
           }
           break;

       case SB_SLIDERPOSITION:

          /*
           * adjust the slider position
           */
           lDeltaScr = ptl.x;
           ptl.x = (LONG)rcl.xLeft - (LONG)SHORT1FROMMP(mp2);
           lDeltaScr = ptl.x - lDeltaScr;
           GpiSetCurrentPosition(vhps, &ptl);
           Scroll((LONG)(SHORT1FROMMP(mp2)), lDeltaScr, HORZSCROLL, &rcl);
           WinInvalidateRect(vhwndClient, &rcl, FALSE);
           break;

       default:
           break;
   }
}   /* End of SizeHScroll */

/**************************************************************************
 *
 *  Name       : SizePositionImage(mp2)
 *
 *  Description: Positions the image correctly within a sized window.

 *  Concepts   : Routine is called MainWndProc() and it invokes
 *               ScrollBars().
 *
 *               - adjust current position of image
 *               - adjust range & position of scrollbars
 *
 *  API's      : GpiSetCurrentPosition
 *               WinQueryWindowRect
 *               GpiQueryCurrentPosition
 *
 *  Parameters :  mp2 = second message parameter
 *
 *  Return     :  [none]
 *
 *************************************************************************/
VOID SizePositionImage(MPARAM mp2)
{
   RECTL  rcl;            /* new window rectangle              */
   POINTL ptl;            /* new current position              */

   WinQueryWindowRect(vhwndClient, &rcl);
   GpiQueryCurrentPosition(vhps, &ptl);

  /*
   * The WM_QUERYTRACKINFO processing ensures that window size never
   * exceeds image size. Here, however, image position in relation to
   * window limits is checked.
   *
   * Set current position such that the image top and right edges are
   * at least at the window limits.
   */

   ptl.y = (ptl.y < rcl.yTop) ? rcl.yTop : ptl.y;
   ptl.x = ((ptl.x + vsizlImg.cx) < rcl.xRight) ?
            (rcl.xRight - rcl.xLeft) - vsizlImg.cx : ptl.x;
   GpiSetCurrentPosition(vhps, &ptl);

  /*
   * adjust scroll-bar positioning and range to new window size
   */
   ScrollBars(SHORT1FROMMP(mp2), SHORT2FROMMP(mp2));
}  /* End of SizePositionImage() */
/***************************  End of img_size.c  *************************/
