// ResizableFormView.cpp : implementation file
//
/////////////////////////////////////////////////////////////////////////////
//
// This file is part of ResizableLib
// http://sourceforge.net/projects/resizablelib
//
// Copyright (C) 2000-2004 by Paolo Messina
// http://www.geocities.com/ppescher - mailto:ppescher@hotmail.com
//
// The contents of this file are subject to the Artistic License (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
// http://www.opensource.org/licenses/artistic-license.html
//
// If you find this code useful, credits would be nice!
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ResizableFormView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CResizableFormView

IMPLEMENT_DYNAMIC(CResizableFormView, CFormView)

inline void CResizableFormView::PrivateConstruct()
{
    m_dwGripTempState = GHR_SCROLLBAR | GHR_ALIGNMENT | GHR_MAXIMIZED;
}

CResizableFormView::CResizableFormView(UINT nIDTemplate)
    : CFormView(nIDTemplate)
{
    PrivateConstruct();
}

CResizableFormView::CResizableFormView(LPCTSTR lpszTemplateName)
    : CFormView(lpszTemplateName)
{
    PrivateConstruct();
}

CResizableFormView::~CResizableFormView()
{
}


BEGIN_MESSAGE_MAP(CResizableFormView, CFormView)
    //{{AFX_MSG_MAP(CResizableFormView)
    ON_WM_SIZE()
    ON_WM_ERASEBKGND()
    ON_WM_GETMINMAXINFO()
    ON_WM_DESTROY()
    ON_WM_NCCREATE()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CResizableFormView diagnostics

#ifdef _DEBUG
void CResizableFormView::AssertValid() const
{
    CFormView::AssertValid();
}

void CResizableFormView::Dump(CDumpContext& dc) const
{
    CFormView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CResizableFormView message handlers

void CResizableFormView::OnSize(UINT nType, int cx, int cy)
{
    CFormView::OnSize(nType, cx, cy);

    CWnd* pParent = GetParentFrame();

    // hide size grip when parent is maximized
    if (pParent->IsZoomed())
        HideSizeGrip(&m_dwGripTempState, GHR_MAXIMIZED);
    else
        ShowSizeGrip(&m_dwGripTempState, GHR_MAXIMIZED);

    // hide size grip when there are scrollbars
    CSize size = GetTotalSize();
    if ((cx < size.cx || cy < size.cy) && (m_nMapMode >= 0))
        HideSizeGrip(&m_dwGripTempState, GHR_SCROLLBAR);
    else
        ShowSizeGrip(&m_dwGripTempState, GHR_SCROLLBAR);

    // hide size grip when the parent frame window is not resizable
    // or the form is not bottom-right aligned (e.g. there's a statusbar)
    DWORD dwStyle = pParent->GetStyle();
    CRect rect, rectChild;
    GetWindowRect(rect);

    BOOL bCanResize = TRUE; // whether the grip can size the frame
    for (HWND hWndChild = ::GetWindow(m_hWnd, GW_HWNDFIRST); hWndChild != NULL;
        hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
    {
        ::GetWindowRect(hWndChild, rectChild);
        //! @todo check RTL layouts!
        if (rectChild.right > rect.right || rectChild.bottom > rect.bottom)
        {
            bCanResize = FALSE;
            break;
        }
    }
    if ((dwStyle & WS_THICKFRAME) && bCanResize)
        ShowSizeGrip(&m_dwGripTempState, GHR_ALIGNMENT);
    else
        HideSizeGrip(&m_dwGripTempState, GHR_ALIGNMENT);

    // update grip and layout
    UpdateSizeGrip();
    ArrangeLayout();
}

void CResizableFormView::GetTotalClientRect(LPRECT lpRect) const
{
    GetClientRect(lpRect);

    // get dialog template's size
    // (this is set in CFormView::Create)
    CSize sizeTotal, sizePage, sizeLine;
    int nMapMode = 0;
    GetDeviceScrollSizes(nMapMode, sizeTotal, sizePage, sizeLine);

    // otherwise, give the correct size if scrollbars active

    if (nMapMode < 0)   // scrollbars disabled
        return;

    // enlarge reported client area when needed
    CRect rect(lpRect);
    if (rect.Width() < sizeTotal.cx)
        rect.right = rect.left + sizeTotal.cx;
    if (rect.Height() < sizeTotal.cy)
        rect.bottom = rect.top + sizeTotal.cy;

    rect.OffsetRect(-GetDeviceScrollPosition());
    *lpRect = rect;
}

BOOL CResizableFormView::OnEraseBkgnd(CDC* pDC)
{
    ClipChildren(pDC, FALSE);

    BOOL bRet = CFormView::OnEraseBkgnd(pDC);

    ClipChildren(pDC, TRUE);

    return bRet;
}

void CResizableFormView::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
    MinMaxInfo(lpMMI);
}

void CResizableFormView::OnDestroy()
{
    RemoveAllAnchors();

    CFormView::OnDestroy();
}

LRESULT CResizableFormView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message == WM_INITDIALOG)
        return (LRESULT)OnInitDialog();

    if (message != WM_NCCALCSIZE || wParam == 0)
        return CFormView::WindowProc(message, wParam, lParam);

    // specifying valid rects needs controls already anchored
    LRESULT lResult = 0;
    HandleNcCalcSize(FALSE, (LPNCCALCSIZE_PARAMS)lParam, lResult);
    lResult = CFormView::WindowProc(message, wParam, lParam);
    HandleNcCalcSize(TRUE, (LPNCCALCSIZE_PARAMS)lParam, lResult);
    return lResult;
}

BOOL CResizableFormView::OnInitDialog()
{
    const MSG* pMsg = GetCurrentMessage();

    BOOL bRet = (BOOL)CFormView::WindowProc(pMsg->message, pMsg->wParam, pMsg->lParam);

    // we need to associate member variables with control IDs
    UpdateData(FALSE);

    // set default scroll size
    CRect rectTemplate;
    GetWindowRect(rectTemplate);
    SetScrollSizes(MM_TEXT, rectTemplate.Size());

    return bRet;
}

BOOL CResizableFormView::OnNcCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (!CFormView::OnNcCreate(lpCreateStruct))
        return FALSE;

    // create and init the size-grip
    if (!CreateSizeGrip())
        return FALSE;

    return TRUE;
}
