TouchBoard/RoundButton2.cpp

585 lines
14 KiB
C++

/********************************************************************
created: 2005/06/03
created: 3:6:2005 13:22
filename: x:\Software\Mfc\Source\Controls\Buttons\RoundButton2.cpp
file path: x:\Software\Mfc\Source\Controls\Buttons
file base: RoundButton2
file ext: cpp
author: Markus Zocholl
purpose: CRoundButton2 defines a universal Button-Control with the
following features:
* Shape is a rounded Rectangle
* Button includes Border and Button-Face
* Many parameters to get an individual look
* Functions of Button to be en- or disabled:
- Button (disabled means a static control with userdefined styles)
- Hover
*********************************************************************/
#include "StdAfx.h"
#include <math.h>
#include ".\RoundButton2.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/************************************************************************/
/* Construction and Destruction */
/************************************************************************/
//! Construction
CRoundButton2::CRoundButton2(void):
m_bDefaultButton(false)
, m_bIsCheckButton(false)
, m_bIsRadioButton(false)
, m_bIsHotButton(false)
, m_bMouseOnButton(false)
, m_bIsChecked(false)
, m_ptRoundButtonStyle(NULL)
, m_rBtnSize(CRect(0, 0, 0, 0))
, m_bRedraw(false)
, m_sOldCaption(_T(""))
{
// Set Standards in Font-Style
m_tLogFont.lfHeight = 16;
m_tLogFont.lfWidth = 0;
m_tLogFont.lfEscapement = 0;
m_tLogFont.lfOrientation = 0;
m_tLogFont.lfWeight = FW_BOLD;
m_tLogFont.lfItalic = false;
m_tLogFont.lfUnderline = false;
m_tLogFont.lfStrikeOut = false;
m_tLogFont.lfCharSet = DEFAULT_CHARSET;
m_tLogFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
m_tLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
m_tLogFont.lfQuality = ANTIALIASED_QUALITY;
m_tLogFont.lfPitchAndFamily = DEFAULT_PITCH;
//strcpy(m_tLogFont.lfFaceName, "Tahoma");
lstrcpy(m_tLogFont.lfFaceName, _T("Tahoma"));
m_tBtnFont.CreateFontIndirect(&m_tLogFont);
// Set Standard Font-Color
m_tTextColor.m_tDisabled = RGB(64, 64, 64);
m_tTextColor.m_tEnabled = RGB( 0, 0, 0);
m_tTextColor.m_tClicked = RGB( 0, 0, 0);
m_tTextColor.m_tPressed = RGB( 0, 0, 0);
m_tTextColor.m_tHot = RGB( 0, 0, 0);
}
//! Destruction
CRoundButton2::~CRoundButton2(void)
{
}
/************************************************************************/
/* public Functions */
/************************************************************************/
// Set Style of Button
bool CRoundButton2::SetRoundButtonStyle(CRoundButtonStyle* _ptRoundButtonStyle)
{
// Check, if Button-Style is given
if (_ptRoundButtonStyle == NULL)
return false;
// Set Pointer to ButtonStyle
m_ptRoundButtonStyle = _ptRoundButtonStyle;
// Redraw Button
m_bRedraw = true;
// All Done
return false;
}
bool CRoundButton2::SetFont(CFont* _ptCFont)
{
if (_ptCFont == NULL)
return false;
LOGFONT logFont;
_ptCFont->GetLogFont(&logFont);
return SetFont(&logFont);
}
// Set Font of Button
bool CRoundButton2::SetFont(LOGFONT* _ptLogFont)
{
if (_ptLogFont == NULL)
return false;
// Delete Font, if already given
if (m_tBtnFont.m_hObject != NULL)
m_tBtnFont.DeleteObject();
// Store Infos local
memcpy(&m_tLogFont, _ptLogFont, sizeof(LOGFONT));
// Create new Font
m_tBtnFont.CreateFontIndirect(&m_tLogFont);
// Button should be redrawn
m_bRedraw = true;
return true;
}
// Set Font of Button
bool CRoundButton2::GetFont(LOGFONT* _ptLogFont)
{
if (_ptLogFont == NULL)
return false;
// Store Infos local
memcpy(_ptLogFont, &m_tLogFont, sizeof(LOGFONT));
return true;
}
//! Set Color of Caption
bool CRoundButton2::SetTextColor(tColorScheme* _ptTextColor)
{
if (_ptTextColor == NULL)
return false;
// Store Infos locally
memcpy(&m_tTextColor, _ptTextColor, sizeof(tColorScheme));
// Button should be redrawn
m_bRedraw = true;
return true;
}
//! Get Color of Caption
bool CRoundButton2::GetTextColor(tColorScheme* _ptTextColor)
{
if (_ptTextColor == NULL)
return false;
// Store Infos locally
memcpy(_ptTextColor, &m_tTextColor, sizeof(tColorScheme));
return true;
}
/************************************************************************/
/* Own Drawing-Functions */
/************************************************************************/
//! Generate Bitmaps to hold Buttons
void CRoundButton2::GenButtonBMPs(CDC* _pDC, CRect _rRect)
{
if (m_tBmpBtn.m_hObject != NULL)
m_tBmpBtn.DeleteObject();
m_tBmpBtn.m_hObject = NULL;
// Generate Bitmap
if (m_tBmpBtn.CreateCompatibleBitmap(_pDC, _rRect.Width(), _rRect.Height() * BS_LAST_STATE) == FALSE)
{
m_rBtnSize = CRect(0, 0, 0, 0);
}
else
{
m_rBtnSize = _rRect;
}
}
//! Draw Button-Face
void CRoundButton2::DrawButtonFace(CDC* _pDC)
{
// We need an attached style
if (m_ptRoundButtonStyle == NULL)
return;
// Get Pointer to Bitmap of Masks
CBitmap* pButtonMasks = m_ptRoundButtonStyle->GetButtonEdge(_pDC);
// Create Memory-DC
CDC SourceDC;
SourceDC.CreateCompatibleDC(_pDC);
// Select Working Objects into DCs
HGDIOBJ hOldBmp1 = SourceDC.SelectObject(pButtonMasks);
int nState;
CSize tEdgeSize = m_ptRoundButtonStyle->GetEdgeSize();
CSize tCorrectedEdgeSize;
CSize tMaskSize = m_ptRoundButtonStyle->GetMaskSize();
// Correct Edge-Size for smaller Buttons
tCorrectedEdgeSize.cx = __min(tEdgeSize.cx, __min(m_rBtnSize.Width() / 2, m_rBtnSize.Height() / 2));
tCorrectedEdgeSize.cy = tCorrectedEdgeSize.cx;
for (nState = 0; nState < BS_LAST_STATE; nState++)
{
/************************************************************************/
/* Draw Edges */
/************************************************************************/
// Left-Top
_pDC->StretchBlt(
0,
nState * m_rBtnSize.Height(),
tCorrectedEdgeSize.cx,
tCorrectedEdgeSize.cy,
&SourceDC,
0,
nState * tMaskSize.cy,
tEdgeSize.cx,
tEdgeSize.cy,
SRCCOPY);
// Left-Bottom
_pDC->StretchBlt(
0,
nState * m_rBtnSize.Height() + m_rBtnSize.Height() - tCorrectedEdgeSize.cy,
tCorrectedEdgeSize.cx,
tCorrectedEdgeSize.cy,
&SourceDC,
0,
nState * tMaskSize.cy + tMaskSize.cy - tEdgeSize.cy,
tEdgeSize.cx,
tEdgeSize.cy,
SRCCOPY);
// Right-Top
_pDC->StretchBlt(
m_rBtnSize.Width() - tCorrectedEdgeSize.cx,
nState * m_rBtnSize.Height(),
tCorrectedEdgeSize.cx,
tCorrectedEdgeSize.cy,
&SourceDC,
tMaskSize.cx - tEdgeSize.cx,
nState * tMaskSize.cy,
tEdgeSize.cx,
tEdgeSize.cy,
SRCCOPY);
// Right-Bottom
_pDC->StretchBlt(
m_rBtnSize.Width() - tCorrectedEdgeSize.cx,
nState * m_rBtnSize.Height() + m_rBtnSize.Height() - tCorrectedEdgeSize.cy,
tCorrectedEdgeSize.cx,
tCorrectedEdgeSize.cy,
&SourceDC,
tMaskSize.cx - tEdgeSize.cx,
nState * tMaskSize.cy + tMaskSize.cy - tEdgeSize.cy,
tEdgeSize.cx,
tEdgeSize.cy,
SRCCOPY);
/************************************************************************/
/* Draw Sides */
/************************************************************************/
// Top
_pDC->StretchBlt(
tCorrectedEdgeSize.cx,
nState * m_rBtnSize.Height(),
m_rBtnSize.Width() - 2 * tCorrectedEdgeSize.cx,
tCorrectedEdgeSize.cy,
&SourceDC,
tEdgeSize.cx,
nState * tMaskSize.cy,
1,
tEdgeSize.cy,
SRCCOPY);
// Bottom
_pDC->StretchBlt(
tCorrectedEdgeSize.cx,
nState * m_rBtnSize.Height() + m_rBtnSize.Height() - tCorrectedEdgeSize.cy,
m_rBtnSize.Width() - 2 * tCorrectedEdgeSize.cx,
tCorrectedEdgeSize.cy,
&SourceDC,
tEdgeSize.cx,
nState * tMaskSize.cy + tMaskSize.cy - tEdgeSize.cy,
1,
tEdgeSize.cy,
SRCCOPY);
// Left
_pDC->StretchBlt(
0,
nState * m_rBtnSize.Height() + tCorrectedEdgeSize.cy,
tCorrectedEdgeSize.cx,
m_rBtnSize.Height() - 2 * tCorrectedEdgeSize.cy,
&SourceDC,
0,
nState * tMaskSize.cy + tEdgeSize.cy,
tEdgeSize.cx,
1,
SRCCOPY);
// Right
_pDC->StretchBlt(
m_rBtnSize.Width() - tCorrectedEdgeSize.cx,
nState * m_rBtnSize.Height() + tCorrectedEdgeSize.cy,
tCorrectedEdgeSize.cx,
m_rBtnSize.Height() - 2 * tCorrectedEdgeSize.cy,
&SourceDC,
tMaskSize.cx - tEdgeSize.cx,
nState * tMaskSize.cy + tEdgeSize.cy,
tEdgeSize.cx,
1,
SRCCOPY);
/************************************************************************/
/* Filling */
/************************************************************************/
_pDC->StretchBlt(
tCorrectedEdgeSize.cx,
nState * m_rBtnSize.Height() + tCorrectedEdgeSize.cy,
m_rBtnSize.Width() - 2* tCorrectedEdgeSize.cx,
m_rBtnSize.Height() - 2 * tCorrectedEdgeSize.cy,
&SourceDC,
tEdgeSize.cx,
nState * tMaskSize.cy + tEdgeSize.cy,
1,
1,
SRCCOPY);
}
// Select Old Objects into DCs
SourceDC.SelectObject(hOldBmp1);
}
//! Draw Caption on Button
void CRoundButton2::DrawButtonCaption(CDC *_pDC)
{
// Select Transparency for Background
int nOldBckMode = _pDC->SetBkMode(TRANSPARENT);
// Get old Text-Color
COLORREF tOldColor = _pDC->SetTextColor(RGB(0,0,0));
// Select Font into DC
HGDIOBJ hOldFont = _pDC->SelectObject(&m_tBtnFont);
// Get Caption of Button
CString sCaption;
this->GetWindowText(sCaption);
for (int nState = 0; nState < BS_LAST_STATE; nState++)
{
switch(nState)
{
case BS_ENABLED:
_pDC->SetTextColor(m_tTextColor.m_tEnabled);
break;
case BS_CLICKED:
_pDC->SetTextColor(m_tTextColor.m_tClicked);
break;
case BS_PRESSED:
_pDC->SetTextColor(m_tTextColor.m_tPressed);
break;
case BS_HOT:
_pDC->SetTextColor(m_tTextColor.m_tHot);
break;
case BS_DISABLED:
default:
_pDC->SetTextColor(m_tTextColor.m_tDisabled);
break;
}
_pDC->DrawText(
sCaption,
CRect(
m_rBtnSize.left,
nState * m_rBtnSize.Height() + m_rBtnSize.top,
m_rBtnSize.right,
nState * m_rBtnSize.Height() + m_rBtnSize.bottom),
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
// Select Old Font back
_pDC->SelectObject(hOldFont);
// Set old Background-Mode
_pDC->SetBkMode(nOldBckMode);
// Set old Text-Color
_pDC->SetTextColor(tOldColor);
}
/************************************************************************/
/* Overwritten Functions for Init and Draw of Button */
/************************************************************************/
//! Presubclass-Window-Function
void CRoundButton2::PreSubclassWindow()
{
#ifdef _DEBUG
// We really should be only sub classing a button control
TCHAR buffer[255];
GetClassName (m_hWnd, buffer, sizeof(buffer) / sizeof(TCHAR));
ASSERT (CString (buffer) == _T("Button"));
#endif
// Check if it's a default button
if (GetStyle() & 0x0FL)
m_bDefaultButton = true;
// Make the button owner-drawn
ModifyStyle (0x0FL, BS_OWNERDRAW | BS_AUTOCHECKBOX, SWP_FRAMECHANGED);
CButton::PreSubclassWindow();
}
//! Draw-Item-Function
/*! This Function is called each time, the Button needs a redraw
*/
void CRoundButton2::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// Get DC of Item
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
ASSERT (pDC != NULL);
// Should Buttons be generated?
bool bGenerate = !m_rBtnSize.EqualRect(&lpDrawItemStruct->rcItem) || m_bRedraw;
// If Rectangles of Button are not the same
if (bGenerate)
{
// Generate Bitmap to hold Buttons
GenButtonBMPs(pDC, lpDrawItemStruct->rcItem);
// Redraw done
m_bRedraw = false;
}
// Generate DC to draw in Memory
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
HGDIOBJ hOldBmp = MemDC.SelectObject(m_tBmpBtn);
CString sActualCaption;
// Get actual caption
GetWindowText(sActualCaption);
// Check, if caption has changed
if (sActualCaption != m_sOldCaption)
bGenerate = true;
// Store old caption
m_sOldCaption = sActualCaption;
// If Rectangles of Button are not the same
if (bGenerate)
{
// Draw Buttons
DrawButtonFace(&MemDC);
// Draw Button-Caption
DrawButtonCaption(&MemDC);
}
int nButtonState;
nButtonState = BS_ENABLED;
if (m_bIsHotButton && m_bMouseOnButton)
nButtonState = BS_HOT;
if ((lpDrawItemStruct->itemState & ODS_DISABLED) == ODS_DISABLED)
nButtonState = BS_DISABLED;
else
{
if ((lpDrawItemStruct->itemState & ODS_SELECTED) == ODS_SELECTED)
nButtonState = BS_PRESSED;
else
{
if (this->m_bIsChecked)
{
nButtonState = BS_CLICKED;
}
}
}
// Copy correct Bitmap to Screen
pDC->BitBlt(
lpDrawItemStruct->rcItem.left,
lpDrawItemStruct->rcItem.top,
m_rBtnSize.Width(),
m_rBtnSize.Height(),
&MemDC,
0,
m_rBtnSize.Height() * nButtonState,
SRCCOPY);
MemDC.SelectObject(hOldBmp);
}
BEGIN_MESSAGE_MAP(CRoundButton2, CButton)
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_CAPTURECHANGED()
END_MESSAGE_MAP()
void CRoundButton2::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_bIsCheckButton)
{
m_bIsChecked = !m_bIsChecked;
}
if (m_bIsRadioButton)
{
m_bIsChecked = true;
}
CButton::OnLButtonUp(nFlags, point);
}
void CRoundButton2::OnMouseMove(UINT nFlags, CPoint point)
{
CRect rcClient;
// Get Rectangle of Client
GetClientRect(rcClient);
// Check, if Mouse is on Control
if (rcClient.PtInRect(point))
{
// We only need to redraw, if the mouse enters
bool bRedrawNeeded = !m_bMouseOnButton;
// Mouse is on Control
m_bMouseOnButton = true;
// Set Capture to recognize, when the mouse leaves the control
SetCapture();
// Redraw Control, if Button is hot
if (m_bIsHotButton)
Invalidate();
}
else
{
// We have lost the mouse-capture, so the mouse has left the buttons face
m_bMouseOnButton = false;
// Mouse has left the button
ReleaseCapture();
// Redraw Control, if Button is hot
if (m_bIsHotButton)
Invalidate();
}
CButton::OnMouseMove(nFlags, point);
}
void CRoundButton2::OnCaptureChanged(CWnd *pWnd)
{
// Check, if we lost the mouse-capture
if (GetCapture() != this)
{
// We have lost the mouse-capture, so the mouse has left the buttons face
m_bMouseOnButton = false;
// Redraw Control, if Button is hot
if (m_bIsHotButton)
Invalidate();
}
CButton::OnCaptureChanged(pWnd);
}