// DDButton.cpp : Implementation of CDDButton
//
// Author : David Shepherd
// Copyright (c) 2003, DaeDoe-Software
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include ".\DDButton.h"
/////////////////////////////////////////////////////////////////////////////
// CDDButton
#pragma warning(push)
#pragma warning(disable: 4355) // 'this' : used in base member initializer list
CDDButton::CDDButton() : 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=ddcpTextAlignCenter;
}
HRESULT CDDButton::FinalConstruct()
{
IMP_BEGIN
// create the default font
m_spFontDisp=CreateDefaultFont();
IMP_END
return RetVal;
}
void CDDButton::FinalRelease()
{
}
const TCHAR* CDDButton::GetObjectFriendlyName()
{
// return the object friendly name
return _T("DDButton");
}
HRESULT CDDButton::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;
}
void CDDButton::OnEnabledChanged()
{
TRY
// update the button
// this is done indirectly by enabling the parent window
if(IsWindow())
{
(void)EnableWindow(VB2B(m_Enabled));
}
CATCH_ALL
}
void CDDButton::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 draw edge type
UINT DrawEdgeType=IsSelected ? EDGE_SUNKEN : EDGE_RAISED;
// draw the edge
if(hDC.DrawEdge(Rect,DrawEdgeType,BF_RECT)==FALSE)
{
throw std::exception();
}
// get the focus rectangle
if(Rect.Width() < 8 or Rect.Height() < 8)
{
Rect.SetRectEmpty(); // there is no room for the focus rectangle
}
else
{
Rect.InflateRect(-4,-4); // there is room for the focus rectangle
}
// adjust the position based on the selected state
if(IsSelected)
{
Rect.OffsetRect(1,1);
}
// draw the focus rectangle
if(HasFocus)
{
CBrush Brush=hDC.GetHalftoneBrush();
if(Brush==NULL)
{
throw std::exception();
}
if(hDC.FrameRect(Rect,Brush)==FALSE)
{
throw std::exception();
}
}
// get the text rectangle
if(Rect.Width() < 4 or Rect.Height() < 4)
{
Rect.SetRectEmpty(); // there is no room for the text
}
else
{
Rect.InflateRect(-2,-2); // there is room for the text
}
// 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,Rect,DrawTextFlags)==0)
{
throw std::exception();
}
}
HRESULT CDDButton::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 CDDButton::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 CDDButton::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// generated by the ATL control wizard
LRESULT lRes = CComControl<CDDButton>::OnSetFocus(uMsg, wParam, lParam, bHandled);
if (m_bInPlaceActive)
{
if(!IsChild(::GetFocus()))
m_ctlButton.SetFocus();
}
return lRes;
}
LRESULT CDDButton::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 CDDButton::OnBNClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
TRY
// fire the click event
__raise Click();
CATCH_ALL
return 0;
}
LRESULT CDDButton::OnButtonEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// to prevent flicker do not erase the background
return TRUE;
}
STDMETHODIMP CDDButton::SetClientSite(IOleClientSite *pClientSite)
{
IMP_BEGIN
// call the base class
HRESULT hr=IOleObjectImpl<CDDButton>::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 CDDButton::SetObjectRects(LPCRECT prcPos,LPCRECT prcClip)
{
// generated by the ATL control wizard
IOleInPlaceObjectWindowlessImpl<CDDButton>::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;
}