// DDCheckBox.cpp : Implementation of CDDCheckBox
//
// Author : David Shepherd
// Copyright (c) 2003, DaeDoe-Software
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include ".\DDCheckBox.h"
/////////////////////////////////////////////////////////////////////////////
// CDDCheckBox
#pragma warning(push)
#pragma warning(disable: 4355) // 'this' : used in base member initializer list
CDDCheckBox::CDDCheckBox() : m_ctlButton(_T("DDButton"), this, 1)
#pragma warning(pop)
{
// initialise everything
m_bWindowOnly=TRUE;
m_Reserved0=0;
m_Reserved1=0;
m_Enabled=VARIANT_TRUE;
m_BackColor=MAKE_OLE_COLOR(COLOR_BTNFACE);
m_ForeColor=MAKE_OLE_COLOR(COLOR_BTNTEXT);
m_TextAlign=ddcpTextAlignLeft;
m_Value=0;
}
HRESULT CDDCheckBox::FinalConstruct()
{
IMP_BEGIN
// create the default font
m_spFontDisp=CreateDefaultFont();
IMP_END
return RetVal;
}
void CDDCheckBox::FinalRelease()
{
}
const TCHAR* CDDCheckBox::GetObjectFriendlyName()
{
// return the object friendly name
return _T("DDCheckBox");
}
HRESULT CDDCheckBox::OnTextAlignChanging(ddcpTextAlign newVal)
{
IMP_BEGIN
// check the new value is valid
if(newVal < ddcpTextAlign_First or newVal > ddcpTextAlign_Last)
{
throw CHResult(E_INVALIDARG);
}
IMP_END
return RetVal;
}
HRESULT CDDCheckBox::OnValueChanging(LONG newVal)
{
IMP_BEGIN
// check the new value is valid
if(newVal!=0 and newVal!=1)
{
throw CHResult(E_INVALIDARG);
}
IMP_END
return RetVal;
}
void CDDCheckBox::OnEnabledChanged()
{
TRY
// update the button
// this is done indirectly by enabling the parent window
if(IsWindow())
{
(void)EnableWindow(VB2B(m_Enabled));
}
CATCH_ALL
}
void CDDCheckBox::DrawButton(
CDCHandle hDC,CRect Rect,BOOL HasFocus,BOOL IsSelected)
{
USES_CONVERSION;
// save the device context state
CAutoDCState AutoDCState(hDC);
// set the background color
COLORREF BackColor=RGB(0,0,0);
if(!SUCCEEDED(OleTranslateColor(m_BackColor,NULL,&BackColor)))
{
throw std::exception();
}
if(hDC.SetBkColor(BackColor)==CLR_INVALID)
{
throw std::exception();
}
// set the foreground color
COLORREF ForeColor=RGB(0,0,0);
if(!SUCCEEDED(OleTranslateColor(m_ForeColor,NULL,&ForeColor)))
{
throw std::exception();
}
if(hDC.SetTextColor(ForeColor)==CLR_INVALID)
{
throw std::exception();
}
// set the font
CComQIPtr<IFont> spFont(m_spFontDisp);
if(spFont==NULL)
{
throw std::exception();
}
CFontHandle hFont;
if(!SUCCEEDED(spFont->get_hFont(&hFont.m_hFont)))
{
throw std::exception();
}
if(hDC.SelectFont(hFont)==NULL)
{
throw std::exception();
}
// fill in the background
hDC.FillSolidRect(Rect,BackColor);
// get the frame control rectangle
CSize FrameControlSize(
GetSystemMetrics(SM_CXMENUCHECK),
GetSystemMetrics(SM_CYMENUCHECK));
CRect FrameControlRect(Rect.TopLeft(),FrameControlSize);
// center vertically
FrameControlRect.OffsetRect(0,(Rect.Height()-FrameControlSize.cy)/2);
// draw the frame control
UINT DrawFrameControlState=DFCS_BUTTONCHECK;
if(IsSelected)
{
DrawFrameControlState |= DFCS_PUSHED;
}
if(m_Value==1)
{
DrawFrameControlState |= DFCS_CHECKED;
}
if(hDC.DrawFrameControl(
FrameControlRect,DFC_BUTTON,DrawFrameControlState)==FALSE)
{
throw std::exception();
}
// determine if the text is visible
const long MinTextLeftPos=FrameControlRect.right+4;
const long MaxTextRightPos=Rect.right-2;
if(MinTextLeftPos < MaxTextRightPos)
{
// get the text rectangle
CSize TextSize(0,0);
if(hDC.GetTextExtent(W2CT(BSTR2W(m_Text)),-1,&TextSize)==FALSE)
{
throw std::exception();
}
CRect TextRect(Rect.TopLeft(),TextSize);
// center vertically
TextRect.OffsetRect(0,(Rect.Height()-TextSize.cy)/2);
// apply the horizontal offset
long dx=MinTextLeftPos;
switch(m_TextAlign)
{
// left
case ddcpTextAlignLeft:
break;
// center
case ddcpTextAlignCenter:
dx+=((MaxTextRightPos-MinTextLeftPos)-TextRect.Width())/2;
break;
// right
case ddcpTextAlignRight:
dx+=(MaxTextRightPos-MinTextLeftPos)-TextRect.Width();
break;
// unknown
default:
ATLASSERT(FALSE);
break;
}
TextRect.OffsetRect(max(dx,MinTextLeftPos),0);
// apply right side clipping
TextRect.right=min(TextRect.right,MaxTextRightPos);
// get the draw text flags
UINT DrawTextFlags=DT_SINGLELINE|DT_VCENTER|DT_NOPREFIX;
switch(m_TextAlign) // text align
{
// left
case ddcpTextAlignLeft:
DrawTextFlags |= DT_LEFT;
break;
// center
case ddcpTextAlignCenter:
DrawTextFlags |= DT_CENTER;
break;
// right
case ddcpTextAlignRight:
DrawTextFlags |= DT_RIGHT;
break;
// unknown
default:
ATLASSERT(FALSE);
break;
}
// draw the text
if(hDC.DrawText(W2CT(BSTR2W(m_Text)),-1,TextRect,DrawTextFlags)==0)
{
throw std::exception();
}
// get the focus rectangle
CRect FocusRect=TextRect;
FocusRect.InflateRect(2,2);
// apply top side clipping
FocusRect.top=max(FocusRect.top,Rect.top);
// apply bottom side clipping
FocusRect.bottom=min(FocusRect.bottom,Rect.bottom);
// draw the focus
if(HasFocus and wcslen(BSTR2W(m_Text))!=0)
{
CBrush Brush=hDC.GetHalftoneBrush();
if(Brush==NULL)
{
throw std::exception();
}
if(hDC.FrameRect(FocusRect,Brush)==FALSE)
{
throw std::exception();
}
}
}
}
HRESULT CDDCheckBox::FireViewChange()
{
IMP_BEGIN
// call the base class
HRESULT hr=CComControlBase::FireViewChange();
if(!SUCCEEDED(hr))
{
throw CHResult(hr);
}
// redraw the button
if(m_ctlButton.IsWindow())
{
(void)m_ctlButton.Invalidate(FALSE);
}
IMP_END
return RetVal;
}
LRESULT CDDCheckBox::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// create the button
if(m_ctlButton.Create(*this,
CRect(0,0,0,0),_T(""),WS_CHILD|WS_VISIBLE|BS_OWNERDRAW)==NULL)
{
throw std::exception();
}
// update the button
if(!SUCCEEDED(put_Enabled(m_Enabled)))
{
throw std::exception();
}
CATCH_ALL
return Caught ? -1 : 0;
}
LRESULT CDDCheckBox::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// generated by the ATL control wizard
LRESULT lRes = CComControl<CDDCheckBox>::OnSetFocus(uMsg, wParam, lParam, bHandled);
if (m_bInPlaceActive)
{
if(!IsChild(::GetFocus()))
m_ctlButton.SetFocus();
}
return lRes;
}
LRESULT CDDCheckBox::OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
TRY
// get the draw item struct
DRAWITEMSTRUCT *pDrawItemStruct=(DRAWITEMSTRUCT *)lParam;
// wrap the device context
CDCHandle hDC=pDrawItemStruct->hDC;
// get the item rectangle
CRect Rect=pDrawItemStruct->rcItem;
// determine if the item has the focus
BOOL HasFocus=(pDrawItemStruct->itemState & ODS_FOCUS) ? TRUE : FALSE;
// determine if the item is selected
BOOL IsSelected=(pDrawItemStruct->itemState & ODS_SELECTED) ? TRUE : FALSE;
// create GDI object wrappers
// this must be done before the memory device context state is saved
CBitmap Bitmap;
// create the memory device context
CDC dcMem;
if(dcMem.CreateCompatibleDC(hDC)==NULL)
{
throw std::exception();
}
// save the memory device context state
CAutoDCState AutoDCState(dcMem);
// create the bitmap and select it into the memory device context
if(Bitmap.CreateCompatibleBitmap(hDC,Rect.Width(),Rect.Height())==NULL)
{
throw std::exception();
}
if(dcMem.SelectBitmap(Bitmap)==NULL)
{
throw std::exception();
}
// map coordinates to the item
if(dcMem.SetWindowOrg(Rect.left,Rect.top)==FALSE)
{
throw std::exception();
}
// draw the button
DrawButton(CDCHandle(dcMem),Rect,HasFocus,IsSelected);
// update the screen
if(hDC.BitBlt(
Rect.left,Rect.top,Rect.Width(),Rect.Height(),
dcMem,Rect.left,Rect.top,SRCCOPY)==FALSE)
{
throw std::exception();
}
CATCH_ALL
return TRUE;
}
LRESULT CDDCheckBox::OnBNClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
TRY
// toggle the value
if(SUCCEEDED(put_Value((m_Value==1) ? 0 : 1)))
{
// fire the click event
__raise Click();
}
CATCH_ALL
return 0;
}
LRESULT CDDCheckBox::OnButtonEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// to prevent flicker do not erase the background
return TRUE;
}
STDMETHODIMP CDDCheckBox::SetClientSite(IOleClientSite *pClientSite)
{
IMP_BEGIN
// call the base class
HRESULT hr=IOleObjectImpl<CDDCheckBox>::SetClientSite(pClientSite);
if(!SUCCEEDED(hr))
{
throw CHResult(hr);
}
// set the background color based on the container ambient properties
OLE_COLOR BackColor=RGB(0,0,0);
if(SUCCEEDED(GetAmbientBackColor(BackColor)))
{
(void)put_BackColor(BackColor);
}
// set the foreground color based on the container ambient properties
OLE_COLOR ForeColor=RGB(0,0,0);
if(SUCCEEDED(GetAmbientForeColor(ForeColor)))
{
(void)put_ForeColor(ForeColor);
}
IMP_END
return RetVal;
}
STDMETHODIMP CDDCheckBox::SetObjectRects(LPCRECT prcPos,LPCRECT prcClip)
{
// generated by the ATL control wizard
IOleInPlaceObjectWindowlessImpl<CDDCheckBox>::SetObjectRects(prcPos, prcClip);
int cx, cy;
cx = prcPos->right - prcPos->left;
cy = prcPos->bottom - prcPos->top;
::SetWindowPos(m_ctlButton.m_hWnd, NULL, 0,
0, cx, cy, SWP_NOZORDER | SWP_NOACTIVATE);
return S_OK;
}
STDMETHODIMP CDDCheckBox::get__Default(LONG* pVal)
{
// delegate to the required default property
return get_Value(pVal);
}
STDMETHODIMP CDDCheckBox::put__Default(LONG newVal)
{
// delegate to the required default property
return put_Value(newVal);
}