Click to return to the Component Development home page    
Web Workshop  |  Component Development

StopLite--StopLiteCtl.CPP


Index for Finished Code

// StopLiteCtl.cpp : Implementation of the CStopLiteCtrl OLE control class.

#include "stdafx.h"
#include "StopLite.h"
#include "StopLiteCtl.h"
#include "StopLitePpg.h"

#include "helpers.h"
#include <objsafe.h&rt;

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


IMPLEMENT_DYNCREATE(CStopLiteCtrl, COleControl)


/////////////////////////////////////////////////////////////////////////////
// Message map

BEGIN_MESSAGE_MAP(CStopLiteCtrl, COleControl)
//{{AFX_MSG_MAP(CStopLiteCtrl)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// Dispatch map

BEGIN_DISPATCH_MAP(CStopLiteCtrl, COleControl)
//{{AFX_DISPATCH_MAP(CStopLiteCtrl)
DISP_PROPERTY_EX(CStopLiteCtrl, "Color", GetColor, SetColor, VT_I2)
DISP_FUNCTION(CStopLiteCtrl, "Next", Next, VT_EMPTY, VTS_NONE)
DISP_DEFVALUE(CStopLiteCtrl, "Color")
DISP_STOCKFUNC_REFRESH()
DISP_STOCKPROP_BACKCOLOR()
DISP_STOCKPROP_FORECOLOR()
//}}AFX_DISPATCH_MAP
DISP_FUNCTION_ID(CStopLiteCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
END_DISPATCH_MAP()


/////////////////////////////////////////////////////////////////////////////
// Event map

BEGIN_EVENT_MAP(CStopLiteCtrl, COleControl)
//{{AFX_EVENT_MAP(CStopLiteCtrl)
EVENT_CUSTOM("Stop", FireStop, VTS_NONE)
EVENT_CUSTOM("Caution", FireCaution, VTS_NONE)
EVENT_CUSTOM("Go", FireGo, VTS_NONE)
EVENT_CUSTOM("Testing", FireTesting, VTS_NONE)
EVENT_CUSTOM("Off", FireOff, VTS_NONE)
EVENT_STOCK_CLICK()
// NOTE - ClassWizard will add and remove event map entries
//    DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_EVENT_MAP
END_EVENT_MAP()


/////////////////////////////////////////////////////////////////////////////
// Property pages

// TODO: Add more property pages as needed.  Remember to increase the count!
BEGIN_PROPPAGEIDS(CStopLiteCtrl, 1)
PROPPAGEID(CStopLitePropPage::guid)
END_PROPPAGEIDS(CStopLiteCtrl)


/////////////////////////////////////////////////////////////////////////////
// Initialize class factory and guid

IMPLEMENT_OLECREATE_EX(CStopLiteCtrl, "STOPLITE.StopLiteCtrl.1",
0x20048bb3, 0xdb68, 0x11cf, 0x9c, 0xaf, 0, 0xaa, 0, 0x6c, 0xb4, 0x25)


/////////////////////////////////////////////////////////////////////////////
// Type library ID and version

IMPLEMENT_OLETYPELIB(CStopLiteCtrl, _tlid, _wVerMajor, _wVerMinor)


/////////////////////////////////////////////////////////////////////////////
// Interface IDs

const IID BASED_CODE IID_DStopLite =
{ 0x20048bb1, 0xdb68, 0x11cf, { 0x9c, 0xaf, 0, 0xaa, 0, 0x6c, 0xb4, 0x25 } };
const IID BASED_CODE IID_DStopLiteEvents =
{ 0x20048bb2, 0xdb68, 0x11cf, { 0x9c, 0xaf, 0, 0xaa, 0, 0x6c, 0xb4, 0x25 } };


/////////////////////////////////////////////////////////////////////////////
// Control type information

static const DWORD BASED_CODE _dwStopLiteOleMisc =
OLEMISC_ACTIVATEWHENVISIBLE |
OLEMISC_SETCLIENTSITEFIRST |
OLEMISC_INSIDEOUT |
OLEMISC_CANTLINKINSIDE |
OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CStopLiteCtrl, IDS_STOPLITE, _dwStopLiteOleMisc)


/////////////////////////////////////////////////////////////////////////////
// CStopLiteCtrl::CStopLiteCtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CStopLiteCtrl

BOOL CStopLiteCtrl::CStopLiteCtrlFactory::UpdateRegistry(BOOL bRegister)
{
// TODO: Verify that your control follows apartment-model threading rules.
// Refer to MFC TechNote 64 for more information.
// If your control does not conform to the apartment-model rules, then
// you must modify the code below, changing the 6th parameter from
// afxRegApartmentThreading to 0.


if (bRegister) {
BOOL retval = AfxOleRegisterControlClass(
AfxGetInstanceHandle(),
m_clsid,
m_lpszProgID,
IDS_STOPLITE,
IDB_STOPLITE,
afxRegApartmentThreading,
_dwStopLiteOleMisc,
_tlid,
_wVerMajor,
_wVerMinor);

// mark as safe for scripting--failure OK
HRESULT hr = CreateComponentCategory(CATID_SafeForScripting, 
L"Controls that are safely scriptable");

if (SUCCEEDED(hr))
// only register if category exists
RegisterCLSIDInCategory(m_clsid, CATID_SafeForScripting);
// don't care if this call fails

// mark as safe for data initialization
hr = CreateComponentCategory(CATID_SafeForInitializing, 
L"Controls safely initializable from persistent data");

if (SUCCEEDED(hr))
// only register if category exists
RegisterCLSIDInCategory(m_clsid, CATID_SafeForInitializing);
// don't care if this call fails

return retval;
}
else
// since unregistering the class automatically eliminates 
// the category registration and since we don't want to 
// remove the categories, we don't need to do anything special

return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}


/////////////////////////////////////////////////////////////////////////////
// CStopLiteCtrl::CStopLiteCtrl - Constructor

CStopLiteCtrl::CStopLiteCtrl()
{
InitializeIIDs(&IID_DStopLite, &IID_DStopLiteEvents);

// TODO: Initialize your control's instance data here.
}


/////////////////////////////////////////////////////////////////////////////
// CStopLiteCtrl::~CStopLiteCtrl - Destructor

CStopLiteCtrl::~CStopLiteCtrl()
{
// TODO: Cleanup your control's instance data here.
}


/////////////////////////////////////////////////////////////////////////////
// CStopLiteCtrl::OnDraw - Drawing function

void CStopLiteCtrl::OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
// 1. erase background using container's background color
CBrush brAmbientBack(TranslateColor(AmbientBackColor()));
pdc->FillRect(rcBounds, &brAmbientBack);

// 2. draw bezel using control's stock properties 
//BackColor and ForeColor
// calculate size based on 40% of height
CRect rcBezel(rcBounds);
int nHeight = rcBounds.Height();
int nWidth = rcBounds.Width();
int nBezelWidth = nHeight * 40 / 100;
if (nBezelWidth > nWidth) 
nBezelWidth = nWidth;// not more then width!
int nDeflateBezel = (nWidth - nBezelWidth) / 2;
rcBezel.DeflateRect(nDeflateBezel, 0);
// create and select brush and pen
CBrush brBack(TranslateColor(GetBackColor()));
CBrush * pbrOld = pdc->SelectObject(&brBack);
CPen pnFore(PS_SOLID, 2, TranslateColor(GetForeColor()));
CPen * ppnOld = pdc->SelectObject(&pnFore);
// draw
pdc->Rectangle(rcBezel);
// select old brush, but not old pen
pdc->SelectObject(pbrOld);

// 3. draw lights using stock ForeColor, already selected
// translate enum code to bits for red, green, yellow
int nLights = TranslateLights();
// percentages are percentage of height
// draw red light on top, 6% down, 27% diameter
DrawLight(pdc, rcBounds, 6, 27, 
(nLights & SLBIT_RED) ? SLCOLOR_RED : SLCOLOR_OFF);
// yellow light in middle, 37% down, 27% diameter
DrawLight(pdc, rcBounds, 37, 27, 
(nLights & SLBIT_YELLOW) ? SLCOLOR_YELLOW : SLCOLOR_OFF);
// green light on bottom, 68% down, 27% diameter
DrawLight(pdc, rcBounds, 68, 27,
(nLights & SLBIT_GREEN) ? SLCOLOR_GREEN : SLCOLOR_OFF);
pdc->SelectObject(ppnOld);
}


/////////////////////////////////////////////////////////////////////////////
// CStopLiteCtrl::DoPropExchange - Persistence support

void CStopLiteCtrl::DoPropExchange(CPropExchange* pPX)
{
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);

// TODO: Call PX_ functions for each persistent custom property.
PX_Short(pPX, "Color", m_color, SL_TEST); 
// default to test state (all on)

// check for load of bad value, fix
if (pPX->IsLoading()) {
if (m_color < SL_NONE || m_color > SL_TEST)  {
m_color = SL_TEST;
}
}
}


/////////////////////////////////////////////////////////////////////////////
// CStopLiteCtrl::OnResetState - Reset control to default state

void CStopLiteCtrl::OnResetState()
{
COleControl::OnResetState();  // Resets defaults found in DoPropExchange

// TODO: Reset any other control state here.
}


/////////////////////////////////////////////////////////////////////////////
// CStopLiteCtrl::AboutBox - Display an "About" box to the user

void CStopLiteCtrl::AboutBox()
{
CDialog dlgAbout(IDD_ABOUTBOX_STOPLITE);
dlgAbout.DoModal();
}


/////////////////////////////////////////////////////////////////////////////
// CStopLiteCtrl message handlers

void CStopLiteCtrl::DrawLight(
// draws an individual light centered in the control at
//vertical position specified
CDC* pdc,// DC in which to draw
const CRect& rcBounds,// control's rectangle
int nPercentDown,// top position as % of height
int nPercentDiameter,// diameter as % of height
COLORREF crColor// color to fill light
)
{

// calculate diameter in drawing units
int nHeight = rcBounds.Height();
int nWidth = rcBounds.Width();
int nDiameter = nHeight * nPercentDiameter / 100;
if (nDiameter > nWidth) 
nDiameter = nWidth;// but not greater than width!

// create light's bounding rect
int nLeftEdge = (rcBounds.left + rcBounds.right - nDiameter) / 2;
int nTopEdge = rcBounds.top + nHeight * nPercentDown / 100;
CRect rcLight(nLeftEdge,
nTopEdge,
nLeftEdge + nDiameter,
nTopEdge + nDiameter);
// make absolutely sure we're within bounds--
// distort circle if necessary!
rcLight.IntersectRect(rcLight, rcBounds);

// create brush, draw, select old brush
CBrush brColor(crColor);
CBrush * brOld = pdc->SelectObject(&brColor);
pdc->Ellipse(rcLight);
pdc->SelectObject(brOld);

}

int CStopLiteCtrl::TranslateLights()
// sets appropriate bits for stoplight state
{
int nLights = SLBIT_RED;// safe default
switch (m_color) {
case SL_NONE: nLights = 0;
break;
case SL_RED: nLights = SLBIT_RED;
break;
case SL_GREEN: nLights = SLBIT_GREEN;
break;
case SL_YELLOW: nLights = SLBIT_YELLOW;
break;
case SL_TEST: nLights = SLBIT_RED | SLBIT_YELLOW | SLBIT_GREEN;
break;
}
return nLights;
}

void CStopLiteCtrl::Next() 
// changes stoplight to next state, redraws
{
if (m_color >= SL_LAST || m_color < SL_FIRST)  {
m_color = SL_FIRST;
}
else m_color++;
InvalidateControl();
FireRightEvent();
SetModifiedFlag();
}

short CStopLiteCtrl::GetColor() 
{
return m_color;
}

void CStopLiteCtrl::SetColor(short nNewValue)
// set color, redraw; throw error if parameter bad
{
if (nNewValue >= SL_NONE && nNewValue <= SL_TEST)  {
m_color = nNewValue;
InvalidateControl();
FireRightEvent();
SetModifiedFlag();
}
else {
ThrowError(CTL_E_ILLEGALFUNCTIONCALL, 
"Color parameter out of range");
}
}

void CStopLiteCtrl::FireRightEvent()
// called whenever the stoplight state changes to fire the
//appropriate event--must call AFTER m_color set to new value!
// Use the source browser to make sure you call each time 
//m_color changed!
{
switch (m_color) {
case SL_RED: FireStop();
break;
case SL_YELLOW: FireCaution();
break;
case SL_GREEN: FireGo();
break;
case SL_NONE: FireOff();
break;
case SL_TEST: FireTesting();
break;
}
}


void CStopLiteCtrl::OnAmbientPropertyChange(DISPID dispid) 
{
// Repaint if ambient background changed or if several changed
if (dispid == DISPID_AMBIENT_BACKCOLOR ||
dispid == DISPID_UNKNOWN) 
{
InvalidateControl();
}

// pass on to base class
COleControl::OnAmbientPropertyChange(dispid);
}

void CStopLiteCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
// call Next method on left click, allow Click stock event to be fired
{
Next();

COleControl::OnLButtonDown(nFlags, point);
}



Back to topBack to top

Did you find this material useful? Gripes? Compliments? Suggestions for other articles? Write us!

© 1999 Microsoft Corporation. All rights reserved. Terms of use.