// ProgressBar.cpp : implementation file
//
// Drop-in status bar progress control
//
// Written by Chris Maunder (chrismaunder@codeguru.com)
// Copyright (c) 1998.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is 
// not sold for profit without the authors written consent, and 
// providing that this notice and the authors name is included. If 
// the source code in this file is used in any commercial application 
// then an email to me would be nice.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage to your
// computer, causes your pet cat to fall ill, increases baldness or
// makes you car start emitting strange noises when you start it up.
//
// Expect bugs.
// 
// Please use and enjoy. Please let me know of any bugs/mods/improvements 
// that you have found/implemented and I will fix/incorporate them into this
// file.
//
// Version 1.1  Chris Maunder (chrismaunder@codeguru.com)
//
// Version 1.2  Michael Martin 07 Aug 1998	mmartin@netspace.net.au
//              Added code to enable progress bar to appear in any pane
//              of the status bar.
//
//              Chris Maunder 17 Aug 1998 
//              Fixed Pane text restoration, and general cleanup.
//
/////////////////////////////////////////////////////////////////////////////
	
#include "stdafx.h"
#include "ProgressBar.h"

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

IMPLEMENT_DYNCREATE(CProgressBar, CProgressCtrl)

BEGIN_MESSAGE_MAP(CProgressBar, CProgressCtrl)
	//{{AFX_MSG_MAP(CProgressBar)
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

CProgressBar::CProgressBar()
{
	m_Rect.SetRect(0,0,0,0);
}

CProgressBar::CProgressBar(LPCTSTR strMessage, int nSize /*=100*/, 
						   int MaxValue /*=100*/, BOOL bSmooth /*=FALSE*/, 
                           int nPane/*=0*/)
{
	Create(strMessage, nSize, MaxValue, bSmooth, nPane);
}

CProgressBar::~CProgressBar()
{
	Clear();
}

CStatusBar* CProgressBar::GetStatusBar()
{
	CWnd *pMainWnd = AfxGetMainWnd();
	if (!pMainWnd)
		return NULL;

    // If main window is a frame window, use normal methods...
    if (pMainWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)))
    {
        CWnd* pMessageBar = ((CFrameWnd*)pMainWnd)->GetMessageBar();
        return DYNAMIC_DOWNCAST(CStatusBar, pMessageBar);
    }
    // otherwise traverse children to try and find the status bar...
    else
	    return DYNAMIC_DOWNCAST(CStatusBar, 
                                pMainWnd->GetDescendantWindow(AFX_IDW_STATUS_BAR));
}

// Create the CProgressCtrl as a child of the status bar positioned
// over the first pane, extending "nSize" percentage across pane.
// Sets the range to be 0 to MaxValue, with a step of 1.
BOOL CProgressBar::Create(LPCTSTR strMessage, int nSize /*=100*/, 
						  int MaxValue /*=100*/, BOOL bSmooth /*=FALSE*/, int nPane/*=0*/)
{
	BOOL bSuccess = FALSE;

	CStatusBar *pStatusBar = GetStatusBar();
	if (!pStatusBar)
		return FALSE;

	DWORD dwStyle = WS_CHILD|WS_VISIBLE;
#ifdef PBS_SMOOTH	 
	if (bSmooth)
		dwStyle |= PBS_SMOOTH;
#endif

	// Get CRect coordinates for requested status bar pane
	CRect PaneRect;
	pStatusBar->GetItemRect(nPane, &PaneRect);

	// Set members
	m_strMessage  = strMessage;
	m_nSize 	  = nSize;
	m_nPane 	  = nPane;
    m_strPrevText = pStatusBar->GetPaneText(m_nPane); 

	Resize();
	
	// Create the progress bar
//	bSuccess = CProgressCtrl::Create(dwStyle, PaneRect, pStatusBar, 1);
	bSuccess = CProgressCtrl::Create(dwStyle, m_Rect, pStatusBar, 1);
	ASSERT(bSuccess);
	if (!bSuccess)
		return FALSE;

	// Set range and step
	SetRange(0, MaxValue);
	SetStep(1);

	// Resize the control to its desired width
//	Resize();

	return TRUE;
}

void CProgressBar::Clear()
{
	if (!IsWindow(GetSafeHwnd()))
		return;

	// Hide the window. This is necessary so that a cleared
	// window is not redrawn if "Resize" is called
	ModifyStyle(WS_VISIBLE, 0);

	CString str;
	if (m_nPane == 0)
		str.LoadString(AFX_IDS_IDLEMESSAGE);   // Get the IDLE_MESSAGE
      else
		str = m_strPrevText;                   // Restore previous text

	// Place the IDLE_MESSAGE in the status bar 
	CStatusBar *pStatusBar = GetStatusBar();
	if (pStatusBar)
	{
		pStatusBar->SetPaneText(m_nPane, str);
		pStatusBar->UpdateWindow();
	}
}

BOOL CProgressBar::SetText(LPCTSTR strMessage)
{ 
	m_strMessage = strMessage; 
	return Resize(); 
}

BOOL CProgressBar::SetSize(int nSize)
{
	m_nSize = nSize; 
	return Resize();
}

COLORREF CProgressBar::SetBarColour(COLORREF clrBar)
{
#ifdef PBM_SETBKCOLOR
	if (!IsWindow(GetSafeHwnd()))
          return CLR_DEFAULT;

	return SendMessage(PBM_SETBARCOLOR, 0, (LPARAM) clrBar);
#else
	UNUSED(clrBar);
	return CLR_DEFAULT;
#endif
}

COLORREF CProgressBar::SetBkColour(COLORREF clrBk)
{
#ifdef PBM_SETBKCOLOR
	if (!IsWindow(GetSafeHwnd()))
		return CLR_DEFAULT;

	return SendMessage(PBM_SETBKCOLOR, 0, (LPARAM) clrBk);
#else
	UNUSED(clrBk);
	return CLR_DEFAULT;
#endif
}

BOOL CProgressBar::SetRange(int nLower, int nUpper, int nStep /* = 1 */)	
{	 
	if (!IsWindow(GetSafeHwnd()))
		return FALSE;

	// To take advantage of the Extended Range Values we use the PBM_SETRANGE32
	// message intead of calling CProgressCtrl::SetRange directly. If this is
	// being compiled under something less than VC 5.0, the necessary defines
	// may not be available.

#ifdef PBM_SETRANGE32
	ASSERT(-0x7FFFFFFF <= nLower && nLower <= 0x7FFFFFFF);
	ASSERT(-0x7FFFFFFF <= nUpper && nUpper <= 0x7FFFFFFF);
	SendMessage(PBM_SETRANGE32, (WPARAM) nLower, (LPARAM) nUpper);
#else
	ASSERT(0 <= nLower && nLower <= 65535);
	ASSERT(0 <= nUpper && nUpper <= 65535);
	CProgressCtrl::SetRange(nLower, nUpper);
#endif
	
	CProgressCtrl::SetStep(nStep);
	return TRUE;
}

int CProgressBar::SetPos(int nPos)	   
{
	if (!IsWindow(GetSafeHwnd()))
		return 0;

#ifdef PBM_SETRANGE32
	ASSERT(-0x7FFFFFFF <= nPos && nPos <= 0x7FFFFFFF);
#else
	ASSERT(0 <= nPos && nPos <= 65535);
#endif

	ModifyStyle(0,WS_VISIBLE);
	return CProgressCtrl::SetPos(nPos);
}

int CProgressBar::OffsetPos(int nPos) 
{ 
	if (!IsWindow(GetSafeHwnd()))
		return 0;

	ModifyStyle(0,WS_VISIBLE);
	return CProgressCtrl::OffsetPos(nPos);
}

int CProgressBar::SetStep(int nStep)
{ 
	if (!IsWindow(GetSafeHwnd()))
		return 0;

	ModifyStyle(0,WS_VISIBLE);
	return CProgressCtrl::SetStep(nStep);	 
}

int CProgressBar::StepIt() 			
{ 
	if (!IsWindow(GetSafeHwnd()))
		return 0;

	ModifyStyle(0,WS_VISIBLE);
	return CProgressCtrl::StepIt();    
}

BOOL CProgressBar::Resize() 
{
//	if (!IsWindow(GetSafeHwnd()))
//		return FALSE;

	CStatusBar *pStatusBar = GetStatusBar();
	if (!pStatusBar)
		return FALSE;

	// Redraw the window text
//	if (IsWindowVisible())
//	{
		pStatusBar->SetPaneText(m_nPane, m_strMessage);
		pStatusBar->UpdateWindow();
//	}

//pStatusBar->GetItemRect(m_nPane, m_Rect);
//return TRUE;

	// Calculate how much space the text takes up
	CDC *pDC = pStatusBar->GetDC();
	CFont *pOldFont = pDC->SelectObject(pStatusBar->GetFont());
	CSize size = pDC->GetTextExtent(m_strMessage);		// Length of text
	int margin = pDC->GetTextExtent(_T(" ")).cx * 2;		// Text margin
	pDC->SelectObject(pOldFont);
	pStatusBar->ReleaseDC(pDC);

	/*
	CClientDC dc(pStatusBar);
	CFont *pOldFont = dc.SelectObject(pStatusBar->GetFont());
	CSize size = dc.GetTextExtent(m_strMessage);		// Length of text
	int margin = dc.GetTextExtent(_T(" ")).cx * 2;		// Text margin
	dc.SelectObject(pOldFont);
	*/

	// Now calculate the rectangle in which we will draw the progress bar
	CRect rc;
	pStatusBar->GetItemRect(m_nPane, rc);

	// Position left of progress bar after text and right of progress bar
	// to requested percentage of status bar pane
	if (!m_strMessage.IsEmpty())
	    rc.left += (size.cx + 2*margin);
//	rc.right -= (rc.right - rc.left) * (100 - m_nSize) / 100;
	rc.right = rc.left + m_nSize;

	if (rc.right < rc.left) rc.right = rc.left;
	
	// Leave a litle vertical margin (10%) between the top and bottom of the bar
	int Height = rc.bottom - rc.top;
	rc.bottom -= Height/10;
	rc.top	  += Height/10;

	// If the window size has changed, resize the window
//	if (rc != m_Rect)
//	{
//		MoveWindow(&rc);
		m_Rect = rc;
//	}

	return TRUE;
}

BOOL CProgressBar::OnEraseBkgnd(CDC* pDC) 
{
	Resize();
	return CProgressCtrl::OnEraseBkgnd(pDC);
}

