/*resize.c*/

#define STRICT
#include <windows.h>
#include "resize.rh"

/*struct for containing sizes*/
typedef struct
    {
    HWND hControl;
    RECT rect;
    } resizeinfo;

/* prototypes */
BOOL    CALLBACK   AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ;
BOOL    CALLBACK   ResizeEnumProc (HWND, LPARAM);
LRESULT FAR PASCAL WndProc (HWND, UINT, WPARAM, LPARAM) ;
resizeinfo GetResizeInfo(HWND hwnd);

/* global variables */
HINSTANCE hInst;
char szAppName[] = "resize" ;
double dVResize, dHResize;
BOOL bEntrance;
int iVSize, iHSize;
int iCurrentHeight, iCurrentWidth;
int iOriginalHeight, iOriginalWidth;
resizeinfo *pri;
int iChildren, iCurrentChild;


int pascal WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPSTR szCmdLine, int iCmdShow) 
    {
    WNDCLASS wndclass ;

    wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
    wndclass.style         = 0 ;
    wndclass.lpfnWndProc   = WndProc ;
    wndclass.cbClsExtra    = 0 ;
    wndclass.cbWndExtra    = DLGWINDOWEXTRA ;/* very important */
    wndclass.hInstance     = hInstance ;
    wndclass.hIcon         = LoadIcon (hInstance, "resizeicon") ;
    wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
    wndclass.hbrBackground = (HBRUSH) GetStockObject (LTGRAY_BRUSH);
    wndclass.lpszMenuName  = "resizemenu" ;
    wndclass.lpszClassName = szAppName ;

    RegisterClass (&wndclass) ;

    hInst=hInstance;

    /*creates a modeless dialog window*/
    DialogBox( hInstance, "resizedialog", NULL, (DLGPROC) WndProc);

    return 0;
    }

/*this windproc is the callback function which processes messages
  for the main window (dialog client)*/
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg,
                          WPARAM wParam, LPARAM lParam)
    {
    WNDENUMPROC wndenmprc;
    RECT rect;

    switch (iMsg) 
        {

        case WM_INITDIALOG:
            bEntrance=TRUE;
            return TRUE;

        case WM_SIZE: 
            {

            /*if this is minimized*/
            if(wParam==SIZE_MINIMIZED)
                return 0;

            GetWindowRect(hwnd, &rect);
            wndenmprc = (WNDENUMPROC) MakeProcInstance
                          ((FARPROC)ResizeEnumProc, hInst);
            if(bEntrance)
                {
                /*find out how many children there are,
                  then make the array of structs to hold
                  the sizes*/
                iChildren=0;
                EnumChildWindows (hwnd, wndenmprc, 0L) ;

                /*allocate memory to store the resize structs*/ 
                pri=malloc (iChildren*sizeof(resizeinfo));

                /*Get all the original sizes into the array*/
                iCurrentChild=0;
                EnumChildWindows (hwnd, wndenmprc, 1L) ;

                /*original window size*/
                iOriginalWidth=rect.right-rect.left;
                iOriginalHeight=rect.bottom-rect.top;
                bEntrance=FALSE;
                return 0;
                }


                /*the next 2 lines and 2 if statements are for 
                  enforcing the minimum size of the dialog.  If it 
                  can be shrunk to any size, comment the next two 
                  lines and ifs out*/
                iCurrentWidth=rect.right-rect.left;
                iCurrentHeight=rect.bottom-rect.top;
                if(iCurrentHeight<iOriginalHeight)
                    {
                    iCurrentHeight=iVSize=iOriginalHeight;
                    MoveWindow(hwnd, rect.left, rect.top,
                               iCurrentWidth, iVSize, TRUE);
                    return 0;
                    }
                if(iCurrentWidth<iOriginalWidth)
                    {
                    iCurrentWidth=iHSize=iOriginalWidth;
                    MoveWindow(hwnd, rect.left, rect.top, iHSize,
                               iCurrentHeight, TRUE);
                    return 0;
                    }

                /*figure out how much to shrink or
                  expand the controls*/
                dVResize=(double)iCurrentHeight/
                         (double)iOriginalHeight;
                dHResize=(double)iCurrentWidth/
                         (double)iOriginalWidth;

                /*run through and resize the children*/
                EnumChildWindows (hwnd, wndenmprc, 2L) ;
                }
            return 0 ;


        /*process events from the controls*/
        case WM_COMMAND :
            switch (LOWORD(wParam))
                {
                case IDC_QUIT :
                    SendMessage(hwnd, WM_DESTROY, 0, 0);
                    break;

                case IDC_ABOUT :
                    DialogBox (hInst, "AboutBox", hwnd,
                               (DLGPROC)AboutDlgProc);
                    break;

                 }/*done switching on wParam*/
            break ;

        case WM_DESTROY :
            /*free the memory allocated for the resize structs*/
            free (pri);
            PostQuitMessage(0);
            return 0;
     }

     return (DefWindowProc(hwnd, iMsg, wParam, lParam)) ;
}/* end of wndproc*/


/*conventional about dialog proc*/
BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT iMsg,
                            WPARAM wParam, LPARAM lParam){
    switch (iMsg)
        {
        case WM_INITDIALOG :
            return TRUE ;

        case WM_COMMAND :
            switch (LOWORD (wParam))
                {
                case IDOK :
                    EndDialog (hDlg, 0) ;
                    return TRUE ;

                }
            break ;
        }
    return FALSE ;
}


/*this is where the children are resized*/
BOOL CALLBACK ResizeEnumProc (HWND hwnd, LPARAM lParam)
    {
    char szClassName [31];
    RECT   rect;
    int iLeft, iTop, iWidth, iHeight;
    POINT pTop, pBottom;
    resizeinfo ri;


    /*counting children*/
    if(lParam==0L)
        {iChildren++; return TRUE;}
    if(!GetWindowRect(hwnd, &rect))
        {;/*can't do anything if this fails*/ }
    /*getting the initial child size*/
    else if(lParam==1L)
        {
        ri.hControl=hwnd;
        pTop.x=rect.left;
        pTop.y=rect.top;
        pBottom.x=rect.right;
        pBottom.y=rect.bottom;
        ScreenToClient(GetParent(hwnd), &pTop);
        ScreenToClient(GetParent(hwnd), &pBottom);

        rect.left=pTop.x;
        rect.top=pTop.y;
        rect.right=pBottom.x;
        rect.bottom=pBottom.y;

        ri.rect=rect;
        pri[iCurrentChild++]=ri;
        }
    else/*resizing the controls*/
        {
        /*get the correct control*/
        ri=GetResizeInfo(hwnd);

        /*fix the horizontal size and position*/
        iLeft=(int)(dHResize*(double)ri.rect.left);
        iWidth=(int)(dHResize*(double)(ri.rect.right-ri.rect.left));

        /*fix the vertical size and position*/
        iTop=(int)(dVResize*(double)ri.rect.top);

        /*if this is anything other that a single line
          text edit, resize height (for demonstration)*/
        GetClassName(hwnd, szClassName, 30);
        AnsiUpper(szClassName);
        /*show that we can resize based on class*/
        if(strcmp(szClassName, "EDIT")==0)
            {
            LONG l=GetWindowLong(hwnd, GWL_STYLE);
            /*only ES_MULTILINE EDIT controls get resized*/
            if(l&ES_MULTILINE)
                iHeight=(int)(dVResize*
                              (double)(ri.rect.bottom-ri.rect.top));
            else
                iHeight=ri.rect.bottom-ri.rect.top;
            }
        else
            iHeight=(int)(dVResize*
                          (double)(ri.rect.bottom-ri.rect.top));
        /*move the window*/
        MoveWindow(hwnd, iLeft, iTop, iWidth, iHeight, TRUE);
        }
    return TRUE;
    }

/* go through the resize array and get the correct information*/
resizeinfo GetResizeInfo(HWND hwnd)
    {
    resizeinfo ri;
    int i;

    for(i=0; i<iChildren; i++)
        {
        ri=pri[i];
        if(ri.hControl==hwnd)
            return ri;
        }

    /*should never get here*/
    return ri;
    }


