/***
*statbar.cpp
*
*  Copyright (C) 1992, Microsoft Corporation.  All Rights Reserved.
*  Information Contained Herein Is Proprietary and Confidential.
*
*Purpose:
*
*Implementation Notes:
*
*****************************************************************************/

#include <stdarg.h>

#include <windows.h>
#include <ole2.h>
#include <dispatch.h>
#include <string.h>

#include "statbar.h"


extern "C" long FAR PASCAL StatBarWndProc(HWND, UINT, WPARAM, LPARAM);


char FAR* CStatBar::m_szWndClass = "StatBarWndClass";


CStatBar::CStatBar()
{
	m_refs = 0;

	m_x = 0;
	m_y = 0;
	m_width = 0;
	m_height = 0;

	m_bstrMsg = NULL;

	m_hfont = (HANDLE)0;
}

CStatBar::~CStatBar()
{
	SysFreeString(m_bstrMsg);
}


/***
*PUBLIC CStatBar FAR* CStatBar::Create(HANDLE, HWND)
*
*Purpose:
*
*Entry:
*
*Exit:
*
***********************************************************************/
CStatBar FAR*
CStatBar::Create(HANDLE hinst, HWND hwndFrame)
{
	CStatBar FAR* psb;

	psb = new FAR CStatBar();
	if(psb == NULL)
	  return NULL;
	psb->AddRef();

	if(!psb->Register(hinst))
	  goto LFail;

	psb->m_hwnd = CreateWindow(
	  CStatBar::m_szWndClass,
	  NULL,
	  WS_CHILD | WS_CLIPSIBLINGS,
	  0, 0, 0, 0,
	  hwndFrame,
	  0,
	  hinst,
	  NULL);

	if(!psb->m_hwnd)
	  goto LFail;

	// Stash the newly created CStatBar* in the extra bytes of the
	// associated window so we can get at the instance in the message
	// proc.
	//
	// Note: we do not AddRef for this reference. We make sure that the
	// window is destroyed when the refcnt goes to 0.
	//
	SetWindowLong(psb->m_hwnd, 0, (LONG)psb);

	return psb;

LFail:;
	delete psb;
	return NULL;
}


//---------------------------------------------------------------------
//                     IUnknown Methods
//---------------------------------------------------------------------


STDMETHODIMP
CStatBar::QueryInterface(REFIID riid, void FAR* FAR* ppv)
{
	if(riid == IID_IUnknown){
	  *ppv = this;
	  AddRef();
	  return NOERROR;
	}
	*ppv = (void FAR*)NULL;
	return ResultFromScode(E_NOINTERFACE);
}


STDMETHODIMP_(unsigned long)
CStatBar::AddRef(void)
{
	return ++m_refs;
}


STDMETHODIMP_(unsigned long)
CStatBar::Release(void)
{
	if(--m_refs == 0){

	  // destroy the status bar window.
	  //
	  SendMessage(m_hwnd, WM_DESTROY, 0, 0L);

	  delete this;
	  return 0;
	}

	return m_refs;
}


//---------------------------------------------------------------------
//                     Introduced Methods
//---------------------------------------------------------------------


/***
*PRIVATE BOOL CStatBar::Register(HANDLE)
*
*Purpose:
*  Register the status bar window class.
*
*Entry:
*  None
*
*Exit:
*  return value = BOOL, TRUE if successful, FALSE if not.
*
***********************************************************************/
BOOL
CStatBar::Register(HANDLE hinst)
{
	WNDCLASS  wc;

	// register the class, unless already registered.
	if(GetClassInfo(hinst, m_szWndClass, &wc) == 0){
	  wc.style         = 0;
	  wc.lpfnWndProc   = StatBarWndProc;
	  wc.cbClsExtra    = 0;
	  wc.cbWndExtra    = sizeof(CStatBar FAR*);
	  wc.hInstance     = hinst;
	  wc.hIcon         = 0;
	  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
	  wc.hbrBackground = GetStockObject(LTGRAY_BRUSH);
	  wc.lpszMenuName  = 0;
	  wc.lpszClassName = CStatBar::m_szWndClass;
	  if(!RegisterClass(&wc))
		return FALSE;
	}
	return TRUE;
}


/***
*PUBLIC void CStatBar::Show(void)
*
*Purpose:
*  Show the status bar window associated with this CStatBar instance.
*
*Entry:
*  None
*
*Exit:
*  None
*
***********************************************************************/
void
CStatBar::Show()
{
	ShowWindow(m_hwnd, SW_SHOW);
}

void
CStatBar::SetFont(HFONT hfont)
{
	HDC hdc;
	TEXTMETRIC tm;
	HFONT hfontOld;

	// compute the character sizes given this new font.
	//
	hdc = GetDC(m_hwnd);
	hfontOld = SelectObject(hdc, hfont);
	GetTextMetrics(hdc, &tm);
	m_dxFont = tm.tmAveCharWidth;
	m_dyFont = tm.tmHeight + tm.tmExternalLeading;
	SelectObject(hdc, hfontOld);
	ReleaseDC(m_hwnd, hdc);

	m_hfont = hfont;
}

/***
*PRIVATE CStatBar::WMPaint(void)
*
*Purpose:
*  This method is responsible for drawing the status bar, and is called
*  in response to a WM_PAINT message.
*
*Entry:
*  None
*
*Exit:
*  None
*
***********************************************************************/
void
CStatBar::WMPaint()
{
	HDC hdc;
	RECT rcMsg;
	HRGN hrgn;
	HFONT hfontOld;
	PAINTSTRUCT ps;
	HPEN hpenBlack, hpenWhite, hpenGray, hpenOld;

	hdc = BeginPaint(m_hwnd, &ps);

	// compute the message box rect
	//
	rcMsg.top   = 3;
	rcMsg.bottom= m_height - 3;
	rcMsg.left  = m_dxFont;
	rcMsg.right = m_width - m_dxFont;

	// prepare the pens
	//
	hpenWhite   = GetStockObject(WHITE_PEN);
	hpenBlack   = GetStockObject(BLACK_PEN);
	hpenGray    = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));

	// draw a top gray line
	//
	hpenOld = SelectObject(hdc, hpenGray);
#if   defined(WIN16)
	MoveTo(hdc, ps.rcPaint.left, 0);
#elif defined(WIN32)
	MoveToEx(hdc, ps.rcPaint.left, 0, NULL);
#endif
	LineTo(hdc, ps.rcPaint.right, 0);

	// draw a white line just under
	//
	SelectObject(hdc, hpenWhite);
#if   defined(WIN16)
	MoveTo(hdc, ps.rcPaint.left, 1);
#elif defined(WIN32)
	MoveToEx(hdc, ps.rcPaint.left, 1, NULL);
#endif
	LineTo(hdc, ps.rcPaint.right, 1);

	// do not overwrite the background color
	//
	SetBkMode(hdc, TRANSPARENT);

	// message area
	//
	SelectObject(hdc, hpenBlack);
#if   defined(WIN16)
	MoveTo(hdc, rcMsg.left,  rcMsg.bottom);
#elif defined(WIN32)
	MoveToEx(hdc, rcMsg.left,  rcMsg.bottom, NULL);
#endif
	LineTo(hdc, rcMsg.left,  rcMsg.top);
	LineTo(hdc, rcMsg.right, rcMsg.top);

	SelectObject(hdc, hpenWhite);
	LineTo(hdc, rcMsg.right, rcMsg.bottom);
	LineTo(hdc, rcMsg.left,  rcMsg.bottom);

	// select the black pen for writing
	//
	SelectObject(hdc, hpenBlack);

	// select the status bar font to write in
	//
	hfontOld = SelectObject(hdc, m_hfont);

	// set the clipping region
	//
	hrgn = CreateRectRgn(
	  rcMsg.left, rcMsg.top, rcMsg.right, rcMsg.bottom);

	SelectClipRgn(hdc, hrgn);

	// draw the status message
	//
	TextOut(
	  hdc,
	  rcMsg.left + (m_dxFont / 2),
	  rcMsg.top + ((rcMsg.bottom - rcMsg.top - m_dyFont) / 2),
	  m_bstrMsg, SysStringLen(m_bstrMsg));

	// cleanup
	//
	SelectObject(hdc, hpenOld);
	SelectObject(hdc, hfontOld);

	DeleteObject(hrgn);
	DeleteObject(hpenGray);

	EndPaint(m_hwnd, &ps);
}

extern "C" long FAR PASCAL
StatBarWndProc(
	HWND hwnd,
	UINT message,
	WPARAM wParam,
	LPARAM lParam)
{
	CStatBar FAR* psb;

	switch(message){
	case WM_SIZE:
	  return 0;
	case WM_PAINT:
	  psb = (CStatBar FAR*)GetWindowLong(hwnd, 0);
	  psb->WMPaint();
	  return 0;
	}
	return(DefWindowProc(hwnd, message, wParam, lParam));
}


//---------------------------------------------------------------------
//                    Status Bar Utilities
//---------------------------------------------------------------------

extern "C" void
SBprintf(CStatBar FAR* psb, char FAR* szFmt, ...)
{
	va_list args;
static char buf[256];

	va_start(args, szFmt);
	wvsprintf(buf, szFmt, args);
	psb->SetText(buf);
	psb->Update();
}
