www.pudn.com > StyleToolkit_demo_src.zip > StyleButton.cpp
//
// StyleButton.cpp : Version 1.0 - see article at CodeProject.com
//
// Author: Darren Sessions
//
//
// Description:
// StyleButton is a CButton derived control that uses GDI+
// to support alternate image formats
//
// History
// Version 1.0 - 2008 July 1
// - Initial public release
//
// License:
// This software is released under the Code Project Open License (CPOL),
// which may be found here: http://www.codeproject.com/info/eula.aspx
// You are free to use this software in any way you like, except that you
// may not sell this source code.
//
// This software is provided "as is" with no expressed or implied warranty.
// I accept no liability for any damage or loss of business that this
// software may cause.
//
///////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "StyleButton.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// StyleButton
StyleButton::StyleButton()
{
m_pStdImage = NULL;
m_pAltImage = NULL;
m_bHaveBitmaps = FALSE;
m_bHaveAltImage = FALSE;
m_pCurBtn = NULL;
m_bIsDisabled = FALSE;
m_bIsToggle = FALSE;
m_bIsHovering = FALSE;
m_bIsTracking = FALSE;
m_nCurState = STD_STATE;
m_nButtonType = BUTTON_TYPE_INVALID;
m_pToolTip = NULL;
m_bHavePStyle = m_bHaveHStyle = m_bHaveGStyle = NULL;
m_bHaveAltStyle = m_bHaveAltPStyle = m_bHaveAltHStyle = NULL;
}
StyleButton::~StyleButton()
{
if(m_pStdImage) delete m_pStdImage;
if(m_pAltImage) delete m_pAltImage;
if(m_pToolTip) delete m_pToolTip;
}
BEGIN_MESSAGE_MAP(StyleButton, CButton)
//{{AFX_MSG_MAP(StyleButton)
ON_WM_DRAWITEM()
ON_WM_ERASEBKGND()
ON_WM_CTLCOLOR_REFLECT()
ON_WM_MOUSEMOVE()
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//=============================================================================
//
// LoadStdImage()
//
// Purpose: The LoadStdImage() Loads the image for the button. This
// function must be called at a minimum or the button wont do
// anything.
//
// Parameters:
// [IN] id
// resource id, one of the resources already imported with the
// resource editor, usually begins with IDR_
//
// [IN] pType
// pointer to string describing the resource type
//
// Returns: BOOL
// Non zero if successful, otherwise zero
//
//=============================================================================
BOOL StyleButton::LoadStdImage(UINT id, LPCTSTR pType)
{
m_pStdImage = new GResource;
m_nButtonType = BUTTON_TYPE_IMAGE;
return m_pStdImage->Load(id, pType);
}
//=============================================================================
//
// LoadAltImage()
//
// Purpose: The LoadAltImage() Loads the altername image for the button.
// This function call is optional
// Parameters:
// [IN] id
// resource id, one of the resources already imported with the
// resource editor, usually begins with IDR_
//
// [IN] pType
// pointer to string describing the resource type
//
// Returns: BOOL
// Non zero if successful, otherwise zero
//
//=============================================================================
BOOL StyleButton::LoadAltImage(UINT id, LPCTSTR pType)
{
m_bHaveAltImage = TRUE;
m_pAltImage = new GResource;
return (m_pAltImage->Load(id, pType));
}
//=============================================================================
//
// The framework calls this member function when a child control is about to
// be drawn. All the bitmaps are created here on the first call. Every thing
// is done with a memory DC except the background, which get's it's information
// from the parent. The background is needed for transparent portions of PNG
// images. An always on top app (such as Task Manager) that is in the way can
// cause it to get an incorrect background. To avoid this, the parent should
// call the SetBkGnd function with a memory DC when it creates the background.
//
//=============================================================================
HBRUSH StyleButton::CtlColor(CDC* pScreenDC, UINT nCtlColor)
{
if(!m_bHaveBitmaps)
{
// Need to call LoadStdImage or LoadStdStyle at a minimum
ASSERT(m_nButtonType != BUTTON_TYPE_INVALID);
CRect rect;
GetClientRect(rect);
// do everything with a temporary mem dc
MemDC pDC(pScreenDC, rect);
// create a graphics object
Graphics graphics(pDC->m_hDC);
// background
if (m_dcBk.m_hDC == NULL)
{
CRect rect1;
CClientDC clDC(GetParent());
GetWindowRect(rect1);
GetParent()->ScreenToClient(rect1);
CBitmap bmp;
m_dcBk.CreateCompatibleDC(&clDC);
bmp.CreateCompatibleBitmap(&clDC, rect.Width(), rect.Height());
m_dcBk.SelectObject(&bmp);
m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), &clDC, rect1.left, rect1.top, SRCCOPY);
bmp.DeleteObject();
}
// standard image
if (m_dcStd.m_hDC == NULL)
{
PaintBk(pDC);
if(m_nButtonType == BUTTON_TYPE_IMAGE)
{
graphics.DrawImage(*m_pStdImage, 0, 0);
}
else
{
m_StdStyle.PaintStyle(pDC, rect);
}
m_dcStd.Create(pDC, rect);
// standard image pressed
if (m_dcStdP.m_hDC == NULL)
{
PaintBk(pDC);
if(m_nButtonType == BUTTON_TYPE_IMAGE)
{
graphics.DrawImage(*m_pStdImage, 1, 1);
}
else
{
// check for pressed style or create from std
if(m_bHavePStyle)
{
m_StdPStyle.PaintStyle(pDC, rect);
}
else
{
m_StdPStyle = m_StdStyle;
m_StdPStyle.SetPosition(1,1);
m_StdPStyle.m_Stacks[0].Regenerate();
m_StdPStyle.PaintStyle(pDC, rect);
}
}
m_dcStdP.Create(pDC, rect);
}
// standard image hot
if(m_dcStdH.m_hDC == NULL)
{
PaintBk(pDC);
if(m_nButtonType == BUTTON_TYPE_IMAGE)
{
DrawHotBitmap(&graphics, m_pStdImage->m_pBitmap);
}
else
{
// check for hot style or create from std
if(m_bHaveHStyle)
{
m_StdHStyle.PaintStyle(pDC, rect);
}
else
{
m_StdStyle.m_Stacks[0].SetClipping(&graphics);
Bitmap *pBmp = m_StdStyle.GetBitmap(pDC, rect);
DrawHotBitmap(&graphics, pBmp);
delete pBmp;
m_StdStyle.m_Stacks[0].RestoreClipping(&graphics);
}
}
m_dcStdH.Create(pDC, rect);
}
// grayscale image
if(m_dcStdG.m_hDC == NULL)
{
PaintBk(pDC);
if(m_nButtonType == BUTTON_TYPE_IMAGE)
{
DrawGrayBitmap(&graphics, m_pStdImage->m_pBitmap);
}
else
{
// check for disabled style or create from std
if(m_bHaveGStyle)
{
m_StdGStyle.PaintStyle(pDC, rect);
}
else
{
m_StdStyle.m_Stacks[0].SetClipping(&graphics);
Bitmap *pBmp = m_StdStyle.GetBitmap(pDC, rect);
DrawGrayBitmap(&graphics, pBmp);
delete pBmp;
m_StdStyle.m_Stacks[0].RestoreClipping(&graphics);
}
}
m_dcStdG.Create(pDC, rect);
}
}
// alternate image
if( (m_dcAlt.m_hDC == NULL) && (m_bHaveAltImage || m_bHaveAltStyle) )
{
PaintBk(pDC);
if(m_nButtonType == BUTTON_TYPE_IMAGE)
{
graphics.DrawImage(*m_pAltImage, 0, 0);
}
else
{
m_AltStyle.PaintStyle(pDC, rect);
}
m_dcAlt.Create(pDC, rect);
// alternate image pressed
if(m_dcAltP.m_hDC == NULL)
{
PaintBk(pDC);
if(m_nButtonType == BUTTON_TYPE_IMAGE)
{
graphics.DrawImage(*m_pAltImage, 1, 1);
}
else
{
// check for pressed style or create from std
if(m_bHaveAltPStyle)
{
m_AltPStyle.PaintStyle(pDC, rect);
}
else
{
m_AltPStyle = m_AltStyle;
m_AltPStyle.SetPosition(1,1);
m_AltPStyle.m_Stacks[0].Regenerate();
m_AltPStyle.PaintStyle(pDC, rect);
}
}
m_dcAltP.Create(pDC, rect);
}
// alternate image hot
if(m_dcAltH.m_hDC == NULL)
{
PaintBk(pDC);
if(m_nButtonType == BUTTON_TYPE_IMAGE)
{
DrawHotBitmap(&graphics, m_pAltImage->m_pBitmap);
}
else
{
m_AltStyle.m_Stacks[0].SetClipping(&graphics);
Bitmap *pBmp = m_AltStyle.GetBitmap(pDC, rect);
DrawHotBitmap(&graphics, pBmp);
delete pBmp;
m_AltStyle.m_Stacks[0].RestoreClipping(&graphics);
}
m_dcAltH.Create(pDC, rect);
}
}
if(m_pCurBtn == NULL)
{
m_pCurBtn = &m_dcStd;
}
m_bHaveBitmaps = TRUE;
}
return NULL;
}
//=============================================================================
// paint the background
//=============================================================================
void StyleButton::PaintBk(CDC *pDC)
{
CRect rect;
GetClientRect(rect);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &m_dcBk, 0, 0, SRCCOPY);
}
//=============================================================================
// paint the bitmap currently pointed to with m_pCurBtn
//=============================================================================
void StyleButton::PaintBtn(CDC *pDC)
{
CRect rect;
GetClientRect(rect);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), m_pCurBtn, 0, 0, SRCCOPY);
}
//=============================================================================
// enables the toggle mode
// returns if it doesn't have the alternate image
//=============================================================================
void StyleButton::EnableToggle(BOOL bEnable)
{
if(!(m_bHaveAltImage || m_bHaveAltStyle)) return;
m_bIsToggle = bEnable;
// this actually makes it start in the std state since toggle is called before paint
if(bEnable) m_pCurBtn = &m_dcAlt;
else m_pCurBtn = &m_dcStd;
}
//=============================================================================
// sets the image type and disabled state then repaints
//=============================================================================
void StyleButton::SetImage(int type)
{
m_nCurState = type;
(type == DIS_STATE) ? m_bIsDisabled = TRUE : m_bIsDisabled = FALSE;
Invalidate();
}
//=============================================================================
// set the control to owner draw
//=============================================================================
void StyleButton::PreSubclassWindow()
{
// Set control to owner draw
ModifyStyle(0, BS_OWNERDRAW, SWP_FRAMECHANGED);
CButton::PreSubclassWindow();
}
//=============================================================================
// disable double click
//=============================================================================
BOOL StyleButton::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_LBUTTONDBLCLK)
pMsg->message = WM_LBUTTONDOWN;
if (m_pToolTip != NULL)
{
if (::IsWindow(m_pToolTip->m_hWnd))
{
m_pToolTip->RelayEvent(pMsg);
}
}
return CButton::PreTranslateMessage(pMsg);
}
//=============================================================================
// overide the erase function
//=============================================================================
BOOL StyleButton::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}
//=============================================================================
// Paint the button depending on the state of the mouse
//=============================================================================
void StyleButton::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
CDC* pDC = CDC::FromHandle(lpDIS->hDC);
// handle disabled state
if(m_bIsDisabled)
{
m_pCurBtn = &m_dcStdG;
PaintBtn(pDC);
return;
}
BOOL bIsPressed = (lpDIS->itemState & ODS_SELECTED);
// handle toggle button
if(m_bIsToggle && bIsPressed)
{
(m_nCurState == STD_STATE) ? m_nCurState = ALT_STATE : m_nCurState = STD_STATE;
}
// determine which bitmap to copy
if(bIsPressed)
{
if(m_nCurState == STD_STATE)
m_pCurBtn = &m_dcStdP;
else
m_pCurBtn = &m_dcAltP;
}
else if(m_bIsHovering)
{
if(m_nCurState == STD_STATE)
m_pCurBtn = &m_dcStdH;
else
m_pCurBtn = &m_dcAltH;
}
else
{
if(m_nCurState == STD_STATE)
m_pCurBtn = &m_dcStd;
else
m_pCurBtn = &m_dcAlt;
}
// paint the button
PaintBtn(pDC);
}
//=============================================================================
LRESULT StyleButton::OnMouseHover(WPARAM wparam, LPARAM lparam)
//=============================================================================
{
m_bIsHovering = TRUE;
Invalidate();
DeleteToolTip();
// Create a new Tooltip with new Button Size and Location
SetToolTipText(m_tooltext);
if (m_pToolTip != NULL)
{
if (::IsWindow(m_pToolTip->m_hWnd))
{
//Display ToolTip
m_pToolTip->Update();
}
}
return 0;
}
//=============================================================================
LRESULT StyleButton::OnMouseLeave(WPARAM wparam, LPARAM lparam)
//=============================================================================
{
m_bIsTracking = FALSE;
m_bIsHovering = FALSE;
Invalidate();
return 0;
}
//=============================================================================
void StyleButton::OnMouseMove(UINT nFlags, CPoint point)
//=============================================================================
{
if (!m_bIsTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE|TME_HOVER;
tme.dwHoverTime = 1;
m_bIsTracking = _TrackMouseEvent(&tme);
}
CButton::OnMouseMove(nFlags, point);
}
//=============================================================================
//
// Call this member function with a memory DC from the code that paints
// the parents background. Passing the screen DC defeats the purpose of
// using this function.
//
//=============================================================================
void StyleButton::SetBkGnd(CDC* pDC)
{
CRect rect, rectS;
CBitmap bmp, *pOldBitmap;
GetClientRect(rect);
GetWindowRect(rectS);
GetParent()->ScreenToClient(rectS);
m_dcBk.DeleteDC();
m_dcBk.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
pOldBitmap = m_dcBk.SelectObject(&bmp);
m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rectS.left, rectS.top, SRCCOPY);
bmp.DeleteObject();
}
//=============================================================================
// Set the tooltip with a string resource
//=============================================================================
void StyleButton::SetToolTipText(UINT nId, BOOL bActivate)
{
// load string resource
m_tooltext.LoadString(nId);
// If string resource is not empty
if (m_tooltext.IsEmpty() == FALSE)
{
SetToolTipText(m_tooltext, bActivate);
}
}
//=============================================================================
// Set the tooltip with a CString
//=============================================================================
void StyleButton::SetToolTipText(CString spText, BOOL bActivate)
{
// We cannot accept NULL pointer
if (spText.IsEmpty()) return;
// Initialize ToolTip
InitToolTip();
m_tooltext = spText;
// If there is no tooltip defined then add it
if (m_pToolTip->GetToolCount() == 0)
{
CRect rectBtn;
GetClientRect(rectBtn);
m_pToolTip->AddTool(this, m_tooltext, rectBtn, 1);
}
// Set text for tooltip
m_pToolTip->UpdateTipText(m_tooltext, this, 1);
m_pToolTip->SetDelayTime(2000);
m_pToolTip->Activate(bActivate);
}
//=============================================================================
void StyleButton::InitToolTip()
//=============================================================================
{
if (m_pToolTip == NULL)
{
m_pToolTip = new CToolTipCtrl;
// Create ToolTip control
m_pToolTip->Create(this);
m_pToolTip->Activate(TRUE);
}
}
//=============================================================================
void StyleButton::DeleteToolTip()
//=============================================================================
{
// Destroy Tooltip incase the size of the button has changed.
if (m_pToolTip != NULL)
{
delete m_pToolTip;
m_pToolTip = NULL;
}
}
//=============================================================================
void StyleButton::LoadStdStyle(Style style)
//=============================================================================
{
m_StdStyle = style;
m_nButtonType = BUTTON_TYPE_STYLE;
}
//=============================================================================
void StyleButton::LoadHotStyle(Style style)
//=============================================================================
{
m_StdHStyle = style;
m_bHaveHStyle = TRUE;
}
//=============================================================================
void StyleButton::LoadPressedStyle(Style style)
//=============================================================================
{
m_StdPStyle = style;
m_bHavePStyle = TRUE;
}
//=============================================================================
void StyleButton::LoadAltStyle(Style style)
//=============================================================================
{
m_AltStyle = style;
m_bHaveAltStyle = TRUE;
}
//=============================================================================
void StyleButton::LoadAltHotStyle(Style style)
//=============================================================================
{
m_AltHStyle = style;
m_bHaveAltHStyle = TRUE;
}
//=============================================================================
void StyleButton::LoadAltPressedStyle(Style style)
//=============================================================================
{
m_AltPStyle = style;
m_bHaveAltPStyle = TRUE;
}
//=============================================================================
void StyleButton::DrawHotBitmap(Graphics* pGraphics, Bitmap* pBmp)
//=============================================================================
{
ColorMatrix HotMat = { 1.05f, 0.00f, 0.00f, 0.00f, 0.00f,
0.00f, 1.05f, 0.00f, 0.00f, 0.00f,
0.00f, 0.00f, 1.05f, 0.00f, 0.00f,
0.00f, 0.00f, 0.00f, 1.00f, 0.00f,
0.05f, 0.05f, 0.05f, 0.00f, 1.00f };
ImageAttributes ia;
ia.SetColorMatrix(&HotMat);
float width = (float)pBmp->GetWidth();
float height = (float)pBmp->GetHeight();
RectF grect; grect.X=0, grect.Y=0; grect.Width = width; grect.Height = height;
pGraphics->DrawImage((Image*)pBmp, grect, 0, 0, width, height, UnitPixel, &ia);
}
//=============================================================================
void StyleButton::DrawGrayBitmap(Graphics* pGraphics, Bitmap* pBmp)
//=============================================================================
{
ColorMatrix GrayMat = { 0.30f, 0.30f, 0.30f, 0.00f, 0.00f,
0.59f, 0.59f, 0.59f, 0.00f, 0.00f,
0.11f, 0.11f, 0.11f, 0.00f, 0.00f,
0.00f, 0.00f, 0.00f, 1.00f, 0.00f,
0.00f, 0.00f, 0.00f, 0.00f, 1.00f };
ImageAttributes ia;
ia.SetColorMatrix(&GrayMat);
float width = (float)pBmp->GetWidth();
float height = (float)pBmp->GetHeight();
RectF grect; grect.X=0, grect.Y=0; grect.Width = width; grect.Height = height;
pGraphics->DrawImage((Image*)pBmp, grect, 0, 0, width, height, UnitPixel, &ia);
}