#include "xheaders.h"

#include XScrollWindow_i
#include XRect_i
#include XScrollBar_i
#include XFrame_i


/*DOC
CLASS XScrollWindow
FUNCTION XScrollWindow
GROUP constructors/destructors
REMARKS constructs a frame-window which does scrolling automaticaly.
Note that destructors of windows are called automaticaly when a window is closed! (see ~XFrameWindow)

Parameters: XResource * theResourceID   a XResource contains two informations, an ID and a pointer
                                        to a XResourceLibrary. If you want to create a window out of
                                        a resourcefile you must specify the ID (otherwise it can be zero)
                                        and the XResourceLibrary which contains the window-resource.
                                        The window which is created always belongs to the process who
                                        owns the resource library, so if you work with multiple processes
                                        every process must have its own resource library.
            char * theTitle             The title of the window which is displayed in the titlebar
            ULONG theStyleofWindow      You can specify the style of the window with the following defines,
                                        which can be or-ed:

                                           FRM_TITLEBAR     the window gets a titlebar
                                           FRM_SYSMENU      the window gets the system menu
                                           FRM_MINBUTTON    the titlebar get a button to minimize the window
                                           FRM_MAXBUTTON    the titlebar get a button to maximize the window

                                           FRM_CENTER       the window is created in the midle of the workplace

                                           FRM_SIZEBORDER   the windowsize can be changed by the user
                                           FRM_DIALOGBORDER the window gets a thick border
                                           FRM_BORDER       the window gets a thin border

                                           FRM_TASKLIST     the window is displayed in the tasklist

                                           FRM_NOMOVEWITHOWNER  the window dontīt move when the parent is moved
                                           FRM_ICON         the window get an icon wich is identified by theResourceID,
                                                            if the icon is not found in the resource-library, an error ocurses
                                           FRM_ACCELTABLE
                                           FRM_SYSMODAL     the window is displayed system-modal
                                           FRM_SCREENALIGN
                                           FRM_MOUSEALIGN
                                           FRM_HIDEBUTTON
                                           FRM_HIDEMAX
                                           FRM_AUTOICON


                                        there are three static member-variables for default styles

                                           long defaultStyle          default setting for a framewindow
                                           long defaultClientStyle    default setting for windows wich are displayed as a clientwindow of a framewindow
                                           long defaultDialogStyle    default setting for windows wich are displayed as a dialog

                                        Default is defaultStyle.
            XRect * theRectangle        On default a window is created with length and hight of zero. Windows
                                        which are created with an resource template get the size of the template.
                                        Default is NULL.
                                        If theRectangle is specified, the window gets the size of it.
            XFrameWindow * parent       If parent is specified the window is a client of the parent. The
                                        behavior depends on the styles you have set.
                                        Default is NULL.
            BOOL buildFromResource      If this variable is set OOL try to build the window with a resource
                                        template which is identified by theResourceID. If the template is
                                        not found, an error ocurses.
                                        Default is FALSE.
Returns: -
*/
XScrollWindow :: XScrollWindow( XResource * resource,
                 char * title,
                 ULONG style,
                 XRect * rec,
                 XFrameWindow * parent,
                 BOOL build):XFrameWindow( resource, title, style, rec, parent, build)
{
   WinQueryWindowPos( winhandle, &clientSwp);
   scrollPosX = scrollPosY = 0;
   xStep = yStep = 10;
   xPage = yPage = 30;
   if( dlgHandle )
      {
         SWP swp;
         WinQueryWindowPos( dlgHandle, &swp);
         SetVirtualX( swp.cx );
         SetVirtualY( swp.cy );
      }
   else
      {
         SetVirtualX (0);
         SetVirtualY (0);
      }
}


/*DOC
CLASS XScrollWindow
FUNCTION SetVirtualX
GROUP scroll-functions
REMARKS set the virtual x-size of the window
Parameters: LONG x                       virtual x-size
Returns:    -
*/
void XScrollWindow :: SetVirtualX( LONG x)
{
   virtualX = x;
   CalcHorzSize();
}


/*DOC
CLASS XScrollWindow
FUNCTION SetVirtualY
GROUP scroll-functions
REMARKS set the virtual y-size of the window
Parameters: LONG y                       virtual y-size
Returns:    -
*/
void XScrollWindow :: SetVirtualY( LONG y)
{
   virtualY = y;
   CalcVertSize();
}


/*DOC
CLASS XScrollWindow
FUNCTION VScroll
GROUP scroll-functions
REMARKS this function is called when the window-contents must be scrolled vertcal.
On default scrolling is done automaticaly
Parameters: LONG s                       how much pixel to scroll
Returns:    -
*/
void XScrollWindow :: VScroll( LONG s)
{
  SWP swp;
  HWND cl = winhandle, hwnd;

  if( scrollPosY + s > virtualY)
     s = virtualY - scrollPosY;
  if( scrollPosY + s < 0)
     s = -scrollPosY;

  if( dlgHandle)
    cl = dlgHandle;

  HENUM enumWindow = WinBeginEnumWindows( cl );

  WinEnableWindowUpdate( cl, FALSE);
  char buffer[5];
  SHORT cor;
  ULONG style;

  while( (hwnd = WinGetNextWindow( enumWindow)) != 0)
    {
       WinQueryClassName( hwnd, 5, (PSZ) buffer);
       style = WinQueryWindowULong( hwnd, QWL_STYLE);
       if( style & ES_MARGIN && buffer[1] == '6')
          cor = 3;
       else
          cor = 0;
       WinQueryWindowPos( hwnd, &swp);
       swp.y -= s;
       WinSetWindowPos( hwnd, 0, swp.x + cor, swp.y + cor, 0, 0, SWP_MOVE);
    };
  WinEndEnumWindows( enumWindow);
  WinEnableWindowUpdate( cl, TRUE);

  scrollPosY += s;
}


/*DOC
CLASS XScrollWindow
FUNCTION HScroll
GROUP scroll-functions
REMARKS this function is called when the window-contents must be scrolled horizontal.
On default scrolling is done automaticaly
Parameters: LONG s                       how much pixel to scroll
Returns:    -
*/
void XScrollWindow :: HScroll( LONG s )
{
  SWP swp;
  HWND cl = winhandle, hwnd;

  if( dlgHandle)
    cl = dlgHandle;

  HENUM enumWindow = WinBeginEnumWindows( cl );

  if( scrollPosX + s > virtualX)
     s = virtualX - scrollPosX;
  if( scrollPosX + s < 0)
     s = -scrollPosX;

  WinEnableWindowUpdate( cl, FALSE);

  char buffer[5];
  SHORT cor;
  ULONG style;
  while( (hwnd = WinGetNextWindow( enumWindow)) != 0)
    {
       WinQueryClassName( hwnd, 5, (PSZ) buffer);
       style = WinQueryWindowULong( hwnd, QWL_STYLE);
       if( style & ES_MARGIN && buffer[1] == '6')
          cor = 3;
       else
          cor = 0;

       WinQueryWindowPos( hwnd, &swp);
       swp.x -= s;
       WinSetWindowPos( hwnd, 0, swp.x + cor, swp.y + cor, 0, 0, SWP_MOVE);
    };
  WinEndEnumWindows( enumWindow);

  WinEnableWindowUpdate( cl, TRUE);

  scrollPosX += s;
}


MRESULT XScrollWindow::HandleMessage(ULONG msg, MPARAM mp1, MPARAM mp2)
{
 SHORT s = 0;

 switch(msg)
   {
     case OOL_ADDCLIENT:
        SWP swp;
        WinQueryWindowPos( (HWND) mp1, &swp);
        if( swp.cx + swp.x > virtualX - 20)
           {
              virtualX = swp.x + swp.cx + 20;
              CalcHorzSize();
           }
        if( swp.cy + swp.y > virtualY - 20)
           {
              virtualY = swp.y + swp.cy + 20;
              CalcVertSize();
           }
        return 0;
     case WM_HSCROLL:
       {
         switch(SHORT2FROMMP( mp2 ))
           {
             case SB_LINERIGHT:
                s = xStep;
                break;
             case SB_LINELEFT:
                s = -xStep;
                break;
             case SB_PAGELEFT:
                s = -xPage;
                break;
             case SB_PAGERIGHT:
                s=xPage;
                break;
             case SB_ENDSCROLL:
                return 0;
             default:
                s = SHORT1FROMMP( mp2) - scrollPosX;
          }
         HScroll( s );
         if( horz)
            horz->SetPos(scrollPosX);
        }
        return 0;
    case WM_VSCROLL:
      {
        switch(SHORT2FROMMP( mp2))
          {
             case SB_LINEUP:
                s = -yStep;
                break;
             case SB_LINEDOWN:
                s = yStep;
                break;
             case SB_PAGEDOWN:
                s = yPage;
                break;
             case SB_PAGEUP:
                s = -yPage;
                break;
             case SB_ENDSCROLL:
                return 0;
             default:
                s = SHORT1FROMMP( mp2) - scrollPosY;
          }
         VScroll( s );
         if( vert )
            vert->SetPos(scrollPosY);
       }
     return 0;
  case WM_SIZE:
     clientSwp.cx = SHORT1FROMMP(mp2);
     clientSwp.cy = SHORT2FROMMP(mp2);
     CalcHorzSize();
     CalcVertSize();
     break;
  }
// return CallDefProc( msg, mp1, mp2);
   return 0;
}


void XScrollWindow :: CalcHorzSize( void )
{
  if(horz)
     {
         horz->SetSliderSize(clientSwp.cx, virtualX);
         horz->SetRange( 1, virtualX-clientSwp.cx, scrollPosX );
     }
}


/*DOC
CLASS XScrollWindow
FUNCTION AddHorzScroller
GROUP misc
REMARKS display an horizontal scroller
Parameters: -
Returns:    -
*/
void XScrollWindow :: AddHorzScroller ( void )
{
   if( horz != NULL) return;
   scrollPosX = 0;

   if( frameWin)
      frameWin->adds+=1;

   XRect r;
   horz = new XScrollBar( this, &r, 0, SC_HORZ | WIN_VISIBLE);
   WinSetParent( horz->winhandle, frame, FALSE);
   WinSetOwner( horz->winhandle, frame);

   if( vert && dummy == 0)
      AddDummy();

   WinSendMsg( frame, WM_UPDATEFRAME, (MPARAM) FCF_HORZSCROLL, 0);
   CalcHorzSize();
}


void XScrollWindow :: CalcVertSize( void )
{
   if(vert )
      {
         vert->SetSliderSize(clientSwp.cy, virtualY);
         vert->SetRange( 1, virtualY-clientSwp.cy, scrollPosY);
      }
}

/*DOC
CLASS XScrollWindow
FUNCTION AddVertScroller
GROUP misc
REMARKS display an vertical scroller
Parameters: -
Returns:    -
*/
void XScrollWindow :: AddVertScroller ( void )
{
   if( vert != NULL) return;

   scrollPosY = 0;

   if( frameWin)
      frameWin->adds+=1;

   XRect r;
   vert = new XScrollBar( this, &r, 0, SC_VERT | WIN_VISIBLE|SC_AUTO);
   WinSetParent( vert->winhandle, frame, FALSE);
   WinSetOwner( vert->winhandle, frame);

   if( horz && dummy == 0)
      AddDummy();

   WinSendMsg( frame, WM_UPDATEFRAME, (MPARAM) FCF_VERTSCROLL, 0);

   CalcVertSize();
}


/*DOC
CLASS XScrollWindow
FUNCTION DeleteVertScroller
GROUP misc
REMARKS removes the vertical scroller
Parameters: -
Returns:    -
*/
void XScrollWindow :: DeleteVertScroller( void )
{
   if( vert == NULL) return;
   if( frameWin)
      frameWin->adds-=1;

   WinDestroyWindow(vert->winhandle);
   delete vert;
   vert = NULL;
   scrollPosY = 0;
   if( dummy )
      DeleteDummy();
   WinSendMsg( frame, WM_UPDATEFRAME, (MPARAM) FCF_VERTSCROLL, 0);
   CalcHorzSize();
}


/*DOC
CLASS XScrollWindow
FUNCTION DeleteHorzScroller
GROUP misc
REMARKS removes the horizontal scroller
Parameters: -
Returns:    -
*/
void XScrollWindow :: DeleteHorzScroller( void )
{
   if( horz == NULL) return;
   if( frameWin)
      frameWin->adds-=1;
   WinDestroyWindow(horz->winhandle);
   delete horz;
   scrollPosX = 0;
   horz = NULL;
   if( dummy )
      DeleteDummy();
   WinSendMsg( frame, WM_UPDATEFRAME, (MPARAM) FCF_HORZSCROLL, 0);
   CalcVertSize();
}

/*
void XScrollWindow :: SetVertPos( void )
{
   if( vert)
      vert->SetPos(scrollPosY);
}


void XScrollWindow :: SetHorzPos( void )
{
   if( horz)
      horz->SetPos(scrollPosX);
}
*/

MRESULT dummyHandler ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
  if( msg == WM_PAINT )
   {
      RECTL rec;
      HPS hps = WinBeginPaint( hwnd, NULLHANDLE, &rec);
      WinFillRect(hps, &rec, CLR_PALEGRAY);
      WinEndPaint( hps);
   }
 return WinDefWindowProc( hwnd, msg, mp1, mp2);
}


void XScrollWindow :: AddDummy( void )
{
   HAB hab = WinQueryAnchorBlock(frame);
   static BOOL dummyRegistered = FALSE;

   if( dummyRegistered == FALSE)
      {
         WinRegisterClass( hab, (PSZ) "OOL_DUMMY", (PFNWP) dummyHandler, 0, 0);
         dummyRegistered = TRUE;
      }

   if( frameWin)
      frameWin->adds+=1;

   dummy = WinCreateWindow( frame, (PSZ) "OOL_DUMMY", (PSZ)"", WS_VISIBLE,
                        0, 0, 0, 0,
                        frame, HWND_TOP, 0, 0, 0);
}


void XScrollWindow :: DeleteDummy( void )
{
  if( dummy == 0) return;

  if( frameWin)
      frameWin->adds-=1;
  WinDestroyWindow( dummy );
  dummy = 0;
}


XScrollWindow :: ~XScrollWindow()
{
   DeleteHorzScroller();
   DeleteVertScroller();
};

