home *** CD-ROM | disk | FTP | other *** search
/ Using Visual C++ 4 (Special Edition) / Using_Visual_C_4_Special_Edition_QUE_1996.iso / ch11 / calenctl.cpp < prev    next >
C/C++ Source or Header  |  1995-10-26  |  19KB  |  766 lines

  1. // CalenCtl.cpp : Implementation of the CCalenCtrl OLE control class.
  2.  
  3. #include "stdafx.h"
  4. #include "Calen.h"
  5. #include "CalenCtl.h"
  6. #include "CalenPpg.h"
  7. #include "dayppg.h"
  8.  
  9.  
  10. #ifdef _DEBUG
  11. #define new DEBUG_NEW
  12. #undef THIS_FILE
  13. static char THIS_FILE[] = __FILE__;
  14. #endif
  15.  
  16. int DaysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  17.  
  18. char *MonthsInYear[] =
  19. {
  20.     "January",
  21.     "February",
  22.     "March",
  23.     "April",
  24.     "May",
  25.     "June",
  26.     "July",
  27.     "August",
  28.     "September",
  29.     "October",
  30.     "November",
  31.     "December"
  32. };
  33.  
  34. char *DaysOfWeek[] =
  35. {
  36.     "Sun",
  37.     "Mon",
  38.     "Tue",
  39.     "Wed",
  40.     "Thu",
  41.     "Fri",
  42.     "Sat"
  43. };
  44.  
  45. IMPLEMENT_DYNCREATE(CCalenCtrl, COleControl)
  46.  
  47.  
  48. /////////////////////////////////////////////////////////////////////////////
  49. // Message map
  50.  
  51. BEGIN_MESSAGE_MAP(CCalenCtrl, COleControl)
  52.     //{{AFX_MSG_MAP(CCalenCtrl)
  53.     ON_WM_LBUTTONDOWN()
  54.     //}}AFX_MSG_MAP
  55.     ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
  56. END_MESSAGE_MAP()
  57.  
  58.  
  59. /////////////////////////////////////////////////////////////////////////////
  60. // Dispatch map
  61.  
  62. BEGIN_DISPATCH_MAP(CCalenCtrl, COleControl)
  63.     //{{AFX_DISPATCH_MAP(CCalenCtrl)
  64.     DISP_PROPERTY_NOTIFY(CCalenCtrl, "Year", m_year, OnYearChanged, VT_I2)
  65.     DISP_PROPERTY_NOTIFY(CCalenCtrl, "CtrlBorderStyle", m_ctrlBorderStyle, OnCtrlBorderStyleChanged, VT_I2)
  66.     DISP_PROPERTY_NOTIFY(CCalenCtrl, "BorderRiseColor", m_borderRiseColor, OnBorderRiseColorChanged, VT_COLOR)
  67.     DISP_PROPERTY_NOTIFY(CCalenCtrl, "BorderFallColor", m_borderFallColor, OnBorderFallColorChanged, VT_COLOR)
  68.     DISP_PROPERTY_NOTIFY(CCalenCtrl, "BorderNormalColor", m_borderNormalColor, OnBorderNormalColorChanged, VT_COLOR)
  69.     DISP_PROPERTY_NOTIFY(CCalenCtrl, "ThreeD", m_threeD, OnThreeDChanged, VT_BOOL)
  70.     DISP_PROPERTY_NOTIFY(CCalenCtrl, "SelectedDayColor", m_selectedDayColor, OnSelectedDayColorChanged, VT_COLOR)
  71.     DISP_PROPERTY_NOTIFY(CCalenCtrl, "DayColor", m_dayColor, OnDayColorChanged, VT_COLOR)
  72.     DISP_PROPERTY_NOTIFY(CCalenCtrl, "DayBorderStyle", m_dayBorderStyle, OnDayBorderStyleChanged, VT_I2)
  73.     DISP_PROPERTY_NOTIFY(CCalenCtrl, "DayRiseColor", m_dayRiseColor, OnDayRiseColorChanged, VT_COLOR)
  74.     DISP_PROPERTY_NOTIFY(CCalenCtrl, "DayFallColor", m_dayFallColor, OnDayFallColorChanged, VT_COLOR)
  75.     DISP_PROPERTY_EX(CCalenCtrl, "DayFont", GetDayFont, SetDayFont, VT_FONT)
  76.     DISP_PROPERTY_EX(CCalenCtrl, "Day", GetDay, SetDay, VT_I2)
  77.     DISP_PROPERTY_EX(CCalenCtrl, "Month", GetMonth, SetMonth, VT_I2)
  78.     DISP_FUNCTION(CCalenCtrl, "SetDate", SetDate, VT_BOOL, VTS_I2 VTS_I2 VTS_I2)
  79.     DISP_STOCKPROP_BACKCOLOR()
  80.     DISP_STOCKPROP_FORECOLOR()
  81.     DISP_STOCKPROP_FONT()
  82.     //}}AFX_DISPATCH_MAP
  83.     DISP_FUNCTION_ID(CCalenCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
  84. END_DISPATCH_MAP()
  85.  
  86.  
  87. /////////////////////////////////////////////////////////////////////////////
  88. // Event map
  89.  
  90. BEGIN_EVENT_MAP(CCalenCtrl, COleControl)
  91.     //{{AFX_EVENT_MAP(CCalenCtrl)
  92.     EVENT_CUSTOM("Select", FireSelect, VTS_I2)
  93.     EVENT_STOCK_CLICK()
  94.     //}}AFX_EVENT_MAP
  95. END_EVENT_MAP()
  96.  
  97.  
  98. /////////////////////////////////////////////////////////////////////////////
  99. // Property pages
  100.  
  101. // TODO: Add more property pages as needed.  Remember to increase the count!
  102. BEGIN_PROPPAGEIDS(CCalenCtrl, 4)
  103.     PROPPAGEID(CCalenPropPage::guid)
  104.     PROPPAGEID(CLSID_CFontPropPage)
  105.     PROPPAGEID(CLSID_CColorPropPage)
  106.     PROPPAGEID(CDayPropPage::guid)
  107. END_PROPPAGEIDS(CCalenCtrl)
  108.  
  109.  
  110. /////////////////////////////////////////////////////////////////////////////
  111. // Initialize class factory and guid
  112.  
  113. IMPLEMENT_OLECREATE_EX(CCalenCtrl, "CALEN.CalenCtrl.1",
  114.     0xf0464dd3, 0xd57, 0x11cf, 0xb4, 0xcd, 0, 0x80, 0xc8, 0x1a, 0x39, 0x7c)
  115.  
  116.  
  117. /////////////////////////////////////////////////////////////////////////////
  118. // Type library ID and version
  119.  
  120. IMPLEMENT_OLETYPELIB(CCalenCtrl, _tlid, _wVerMajor, _wVerMinor)
  121.  
  122.  
  123. /////////////////////////////////////////////////////////////////////////////
  124. // Interface IDs
  125.  
  126. const IID BASED_CODE IID_DCalen =
  127.         { 0xf0464dd1, 0xd57, 0x11cf, { 0xb4, 0xcd, 0, 0x80, 0xc8, 0x1a, 0x39, 0x7c } };
  128. const IID BASED_CODE IID_DCalenEvents =
  129.         { 0xf0464dd2, 0xd57, 0x11cf, { 0xb4, 0xcd, 0, 0x80, 0xc8, 0x1a, 0x39, 0x7c } };
  130.  
  131.  
  132. /////////////////////////////////////////////////////////////////////////////
  133. // Control type information
  134.  
  135. static const DWORD BASED_CODE _dwCalenOleMisc =
  136.     OLEMISC_ACTIVATEWHENVISIBLE |
  137.     OLEMISC_SETCLIENTSITEFIRST |
  138.     OLEMISC_INSIDEOUT |
  139.     OLEMISC_CANTLINKINSIDE |
  140.     OLEMISC_RECOMPOSEONRESIZE;
  141.  
  142. IMPLEMENT_OLECTLTYPE(CCalenCtrl, IDS_CALEN, _dwCalenOleMisc)
  143.  
  144.  
  145. /////////////////////////////////////////////////////////////////////////////
  146. // CCalenCtrl::CCalenCtrlFactory::UpdateRegistry -
  147. // Adds or removes system registry entries for CCalenCtrl
  148.  
  149. BOOL CCalenCtrl::CCalenCtrlFactory::UpdateRegistry(BOOL bRegister)
  150. {
  151.     if (bRegister)
  152.         return AfxOleRegisterControlClass(
  153.             AfxGetInstanceHandle(),
  154.             m_clsid,
  155.             m_lpszProgID,
  156.             IDS_CALEN,
  157.             IDB_CALEN,
  158.             FALSE,                      //  Not insertable
  159.             _dwCalenOleMisc,
  160.             _tlid,
  161.             _wVerMajor,
  162.             _wVerMinor);
  163.     else
  164.         return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
  165. }
  166.  
  167.  
  168. /////////////////////////////////////////////////////////////////////////////
  169. // CCalenCtrl::CCalenCtrl - Constructor
  170.  
  171. CCalenCtrl::CCalenCtrl()  : m_dayFont(NULL)
  172. {
  173.     InitializeIIDs(&IID_DCalen, &IID_DCalenEvents);
  174.      m_dayFont.InitializeFont();
  175.      SetInitialSize(8*30,8*30);
  176. }
  177.  
  178.  
  179. /////////////////////////////////////////////////////////////////////////////
  180. // CCalenCtrl::~CCalenCtrl - Destructor
  181.  
  182. CCalenCtrl::~CCalenCtrl()
  183. {
  184.     // TODO: Cleanup your control's instance data here.
  185. }
  186.  
  187.  
  188. /////////////////////////////////////////////////////////////////////////////
  189. // CCalenCtrl::OnDraw - Drawing function
  190.  
  191. void CCalenCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, 
  192.                         const CRect& rcInvalid)
  193. {
  194.     // Fill in background 
  195.     CBrush brBack(TranslateColor(GetBackColor()));
  196.     pdc->FillRect(&rcInvalid,&brBack);
  197.  
  198.     DrawBorder(rcBounds,pdc);
  199.     DrawMonth(rcBounds,pdc);
  200.     DrawDaysOfWeek(rcBounds,pdc);
  201.     DrawDays(rcBounds,pdc);
  202.     DrawSelectedDay(TRUE,rcBounds,pdc);
  203. }
  204.  
  205.  
  206. /////////////////////////////////////////////////////////////////////////////
  207. // CCalenCtrl::DoPropExchange - Persistence support
  208.  
  209. void CCalenCtrl::DoPropExchange(CPropExchange* pPX)
  210. {
  211.     ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
  212.     COleControl::DoPropExchange(pPX);
  213.  
  214.     CTime time = CTime::GetCurrentTime();
  215.     PX_Bool(pPX,"ThreeD",m_threeD,FALSE);
  216.     PX_Short(pPX,"CtrlBorderStyle", m_ctrlBorderStyle,0);
  217.     PX_ULong(pPX,"BorderRiseColor", m_borderRiseColor, RGB(255,255,255));
  218.     PX_ULong(pPX,"BorderFallColor", m_borderFallColor, RGB(128,128,128));
  219.     PX_ULong(pPX,"BorderNormalColor", m_borderNormalColor, RGB(0,0,0));
  220.     PX_Font(pPX,"DayFont", m_dayFont,NULL,AmbientFont());
  221.     PX_ULong(pPX,"DayColor", m_dayColor, RGB(192,192,192));
  222.     PX_Short(pPX, "DayBorderStyle", m_dayBorderStyle, 0);
  223.     PX_ULong(pPX, "DayRiseColor", m_dayRiseColor, RGB(255,255,255));
  224.     PX_ULong(pPX, "DayFallColor", m_dayFallColor, RGB(128,128,128));
  225.     PX_Short(pPX, "Month", m_Month, time.GetMonth());
  226.     PX_Short(pPX, "Day", m_Day, time.GetDay());
  227.     PX_Short(pPX, "Year", m_year, time.GetYear());
  228.     PX_ULong(pPX, "SelectedDayColor", m_selectedDayColor, RGB(0,255,64));
  229. }
  230.  
  231.  
  232. /////////////////////////////////////////////////////////////////////////////
  233. // CCalenCtrl::OnResetState - Reset control to default state
  234.  
  235. void CCalenCtrl::OnResetState()
  236. {
  237.     COleControl::OnResetState();  // Resets defaults found in DoPropExchange
  238.  
  239.     // TODO: Reset any other control state here.
  240. }
  241.  
  242.  
  243. /////////////////////////////////////////////////////////////////////////////
  244. // CCalenCtrl::AboutBox - Display an "About" box to the user
  245.  
  246. void CCalenCtrl::AboutBox()
  247. {
  248.     CDialog dlgAbout(IDD_ABOUTBOX_CALEN);
  249.     dlgAbout.DoModal();
  250. }
  251.  
  252.  
  253. /////////////////////////////////////////////////////////////////////////////
  254. // CCalenCtrl message handlers
  255.  
  256. LPFONTDISP CCalenCtrl::GetDayFont() 
  257. {
  258.     return m_dayFont.GetFontDispatch();
  259. }
  260.  
  261. void CCalenCtrl::SetDayFont(LPFONTDISP newValue) 
  262. {
  263.     SetModifiedFlag();
  264.      m_dayFont.InitializeFont(NULL,newValue);
  265.      InvalidateControl();
  266. }
  267.  
  268. short CCalenCtrl::GetDay() 
  269. {
  270.     return m_Day;
  271. }
  272.  
  273. void CCalenCtrl::SetDay(short nNewValue) 
  274. {
  275.     SetModifiedFlag();
  276.  
  277.     // Make some attempt to determine if the day is within a given
  278.     // range.  Note that this does not check for leap years
  279.     ASSERT(m_Month >= 1 && m_Month <= 12);
  280.  
  281.     if(nNewValue <1 ||nNewValue > DaysInMonth[m_Month-1] )
  282.     {
  283.         ThrowError(CTL_E_INVALIDPROPERTYVALUE,
  284.                    "Day is outside of allowable range");
  285.     }
  286.     else
  287.     {
  288.         CRect NullRect(0,0,0,0);
  289.         DrawSelectedDay(FALSE,NullRect);
  290.         m_Day = nNewValue;
  291.         DrawSelectedDay(TRUE,NullRect);
  292.     }
  293. }
  294.  
  295. short CCalenCtrl::GetMonth() 
  296. {
  297.     return m_Month;
  298. }
  299.  
  300. void CCalenCtrl::SetMonth(short nNewValue) 
  301. {
  302.     SetModifiedFlag();
  303.  
  304.     if(nNewValue>0&&nNewValue<13)
  305.       {
  306.         m_Month = nNewValue;
  307.         InvalidateControl();
  308.     }
  309.     else
  310.     {
  311.         ThrowError(CTL_E_INVALIDPROPERTYVALUE,
  312.             "Month is outside of allowable range");
  313.     }
  314. }
  315.  
  316. void CCalenCtrl::OnYearChanged() 
  317. {
  318.     InvalidateControl();
  319.     SetModifiedFlag();
  320. }
  321.  
  322. void CCalenCtrl::OnCtrlBorderStyleChanged() 
  323. {
  324.     CRect NullRect(0,0,0,0);
  325.     DrawBorder(NullRect);
  326.     SetModifiedFlag();
  327. }
  328.  
  329. void CCalenCtrl::OnBorderRiseColorChanged() 
  330. {
  331.     CRect NullRect(0,0,0,0);
  332.     DrawBorder(NullRect);
  333.     SetModifiedFlag();
  334. }
  335.  
  336. void CCalenCtrl::OnBorderFallColorChanged() 
  337. {
  338.     CRect NullRect(0,0,0,0);
  339.     DrawBorder(NullRect);
  340.     SetModifiedFlag();
  341. }
  342.  
  343. void CCalenCtrl::OnBorderNormalColorChanged() 
  344. {
  345.     CRect NullRect(0,0,0,0);
  346.     DrawBorder(NullRect);
  347.     SetModifiedFlag();
  348. }
  349.  
  350. void CCalenCtrl::OnThreeDChanged() 
  351. {
  352.     CRect NullRect(0,0,0,0);
  353.     DrawBorder(NullRect);
  354.     SetModifiedFlag();
  355. }
  356.  
  357. void CCalenCtrl::OnSelectedDayColorChanged() 
  358. {
  359.     InvalidateControl();
  360.     SetModifiedFlag();
  361. }
  362.  
  363. void CCalenCtrl::OnDayColorChanged() 
  364. {
  365.     InvalidateControl();
  366.     SetModifiedFlag();
  367. }
  368.  
  369. void CCalenCtrl::OnDayBorderStyleChanged() 
  370. {
  371.     InvalidateControl();
  372.     SetModifiedFlag();
  373. }
  374.  
  375. void CCalenCtrl::OnDayRiseColorChanged() 
  376. {
  377.     InvalidateControl();
  378.     SetModifiedFlag();
  379. }
  380.  
  381. void CCalenCtrl::OnDayFallColorChanged() 
  382. {
  383.     InvalidateControl();
  384.     SetModifiedFlag();
  385. }
  386.  
  387. void CCalenCtrl::DrawBorder(const CRect& rcBounds, CDC *pDC)
  388. {
  389.     BOOL nullDC = FALSE;
  390.     CRect cRect(rcBounds);
  391.  
  392.     if(pDC==NULL)
  393.     {
  394.         pDC = GetDC();
  395.         GetClientRect(cRect);
  396.         nullDC = TRUE;
  397.     }
  398.  
  399.     if(m_threeD)
  400.     {
  401.         // Determine the border colors based on the control style
  402.         COLORREF clrOne, clrTwo;
  403.         if (m_ctrlBorderStyle == 0)
  404.         {
  405.             //raised
  406.             clrOne = TranslateColor(m_borderRiseColor);
  407.             clrTwo = TranslateColor(m_borderFallColor);
  408.         }
  409.         else
  410.         {
  411.             //inset
  412.             clrOne = TranslateColor(m_borderFallColor);
  413.             clrTwo = TranslateColor(m_borderRiseColor);
  414.         }
  415.  
  416.         CPen LeftTop;
  417.         CPen RightBottom;
  418.  
  419.         // Make sure create pen succeeds and draw our 3D border
  420.         if(LeftTop.CreatePen(PS_SOLID,1,clrOne) 
  421.             && RightBottom.CreatePen(PS_SOLID,1,clrTwo))
  422.         {
  423.             CPen *OldPen = pDC->SelectObject(&LeftTop);
  424.  
  425.             pDC->MoveTo(cRect.left,cRect.bottom-1);
  426.             pDC->LineTo(cRect.left,cRect.top);
  427.             pDC->LineTo(cRect.right-1,cRect.top);
  428.  
  429.             pDC->SelectObject(&RightBottom);
  430.             pDC->LineTo(cRect.right-1,cRect.bottom-1);
  431.             pDC->LineTo(cRect.left-1,cRect.bottom-1);
  432.  
  433.             pDC->SelectObject(OldPen);
  434.         }
  435.     }
  436.     else
  437.     {
  438.         CPen Pen;
  439.         if(Pen.CreatePen(PS_SOLID,1,TranslateColor(m_borderNormalColor)))
  440.         {
  441.             CPen *OldPen = pDC->SelectObject(&Pen);
  442.  
  443.             pDC->MoveTo(cRect.left,cRect.top);
  444.             pDC->LineTo(cRect.right-1,cRect.top);
  445.             pDC->LineTo(cRect.right-1,cRect.bottom-1);
  446.             pDC->LineTo(cRect.left,cRect.bottom-1);
  447.             pDC->LineTo(cRect.left,cRect.top);
  448.  
  449.             pDC->SelectObject(OldPen);
  450.         }
  451.     }
  452.  
  453.     if(nullDC)
  454.         ReleaseDC(pDC);
  455. }
  456.  
  457. void CCalenCtrl::DrawMonth(const CRect& rcBounds, CDC *pdc)
  458. {
  459.     int oldBkMode;
  460.     CFont *oldFont;
  461.     COLORREF oldColor;
  462.  
  463.     BOOL nullDC = FALSE;
  464.     CRect cRect(rcBounds);
  465.     
  466.     if(pdc==NULL)
  467.     {
  468.         pdc = GetDC();
  469.         GetClientRect(cRect);
  470.         nullDC = TRUE;
  471.     }
  472.  
  473.   // Draw the month in the top section of the frame
  474.   CRect littleRect(cRect.left,cRect.top,cRect.left+7*30,cRect.top+30);
  475.   oldFont = SelectStockFont(pdc);
  476.   oldBkMode = pdc->SetBkMode(TRANSPARENT);
  477.   oldColor = pdc->SetTextColor(TranslateColor(GetForeColor()));
  478.   
  479.   pdc->DrawText(MonthsInYear[m_Month-1],lstrlen(MonthsInYear[m_Month-1]),
  480.                                   littleRect,DT_VCENTER|DT_CENTER|DT_SINGLELINE);
  481.                                   
  482.   pdc->SetTextColor(oldColor);
  483.   pdc->SelectObject(oldFont);
  484.   pdc->SetBkMode(oldBkMode);
  485.  
  486.     if(nullDC)
  487.         ReleaseDC(pdc);
  488. }
  489.  
  490. void CCalenCtrl::DrawDaysOfWeek(const CRect& rcBounds, CDC *pdc)
  491. {
  492.     int oldBkMode;
  493.     CFont *oldFont;
  494.      COLORREF oldColor;
  495.  
  496.     CRect cRect(rcBounds);
  497.  
  498.     BOOL nullDC = FALSE;
  499.     
  500.     if(pdc==NULL)
  501.     {
  502.         pdc = GetDC();
  503.         GetClientRect(cRect);
  504.         nullDC = TRUE;
  505.     }
  506.  
  507.   
  508.     oldColor = pdc->SetTextColor(TranslateColor(GetForeColor()));
  509.     oldFont = SelectFontObject(pdc,m_dayFont);
  510.     oldBkMode = pdc->SetBkMode(TRANSPARENT);
  511.  
  512.     // Get a reasonable distance from the start of the days
  513.     CSize cSize = pdc->GetTextExtent("X",1);
  514.     CRect littleRect(cRect.left+16,cRect.top+60-(cSize.cy+10),
  515.         cRect.left+45,cRect.top+60);
  516.     
  517.     // Draw the days of the week
  518.     for(int i=0 ; i<7 ; i++)
  519.     {
  520.       pdc->DrawText(DaysOfWeek[i],lstrlen(DaysOfWeek[i]),littleRect,DT_VCENTER|DT_CENTER|DT_SINGLELINE);
  521.       littleRect.SetRect(cRect.left+16+(i+1)*30,cRect.top+60-(cSize.cy+10),
  522.           cRect.left+16+(i+1)*30+30,cRect.top+60);
  523.     }
  524.                                           
  525.     pdc->SetTextColor(oldColor);
  526.     pdc->SelectObject(oldFont);
  527.     pdc->SetBkMode(oldBkMode);
  528.  
  529.     if(nullDC)
  530.         ReleaseDC(pdc);
  531. }
  532.  
  533. void CCalenCtrl::DrawDays(const CRect& rcBounds, CDC *pdc)
  534. {
  535.     int oldBkMode;
  536.     CFont *oldFont;
  537.     CPen *oldPen;
  538.     COLORREF oldColor;
  539.  
  540.     CRect cRect(rcBounds);
  541.  
  542.     BOOL nullDC = FALSE;
  543.     
  544.     if(pdc==NULL)
  545.         {
  546.         pdc = GetDC();
  547.         GetClientRect(cRect);
  548.         nullDC = TRUE;
  549.         }
  550.  
  551.     // Setup border colors
  552.     COLORREF clrOne, clrTwo;
  553.     if (m_dayBorderStyle == 0)
  554.     {
  555.         //raised
  556.         clrOne = TranslateColor(m_dayRiseColor);
  557.         clrTwo = TranslateColor(m_dayFallColor);
  558.     }
  559.     else
  560.     {
  561.         //inset
  562.         clrOne = TranslateColor(m_dayFallColor);
  563.         clrTwo = TranslateColor(m_dayRiseColor);
  564.     }
  565.   
  566.     oldColor = pdc->SetTextColor(TranslateColor(m_dayColor));
  567.     oldFont = SelectFontObject(pdc,m_dayFont);
  568.     oldBkMode = pdc->SetBkMode(TRANSPARENT);
  569.   
  570.     CRect littleRect;
  571.     CPen LeftTop, RightBottom;
  572.     
  573.      if(LeftTop.CreatePen(PS_SOLID,1,clrOne) 
  574.         && RightBottom.CreatePen(PS_SOLID,1,clrTwo))
  575.     {
  576.           oldPen = pdc->SelectObject(&LeftTop);
  577.   
  578.         int row=0;
  579.         int col = 0;
  580.         CTime time(m_year, m_Month, 1, 1, 1, 1);
  581.         char day[4];
  582.         int firstday = time.GetDayOfWeek() - 1; 
  583.             //day of week is 1-based; row and col are zero-based
  584.         int lastday = firstday + DaysInMonth[m_Month-1];
  585.         //notice this ignores leap years again
  586.         int i;
  587.         while (row < 6)
  588.         {
  589.             i = row*7+col;
  590.             if ( (i >= firstday) && (i <= lastday) )
  591.             {
  592.                 // draw the square
  593.                   littleRect.SetRect(cRect.left+15+2+col*30, 
  594.                     cRect.top+60+row*30+2, cRect.left+45-2+30*col, 
  595.                     cRect.top+90-2+row*30);
  596.                   pdc->MoveTo(littleRect.left,littleRect.bottom);
  597.                   pdc->SelectObject(&LeftTop);
  598.                   pdc->LineTo(littleRect.left,littleRect.top);
  599.                   pdc->LineTo(littleRect.right,littleRect.top);
  600.   
  601.                   pdc->SelectObject(&RightBottom);
  602.                   pdc->LineTo(littleRect.right,littleRect.bottom);
  603.                   pdc->LineTo(littleRect.left,littleRect.bottom);    
  604.    
  605.                 // Draw the day number
  606.                 sprintf(day, "%d", (i - firstday + 1));
  607.                 pdc->TextOut(littleRect.left + 2, littleRect.top + 2, 
  608.                     day, lstrlen(day));
  609.             }
  610.             if (col == 6)
  611.             {
  612.                 row++;
  613.                 col = 0;
  614.             }
  615.             else
  616.             {
  617.                 col++;
  618.             }
  619.         }
  620.     }
  621.             
  622.     pdc->SetTextColor(oldColor);
  623.     pdc->SelectObject(oldPen);
  624.     pdc->SelectObject(oldFont);
  625.     pdc->SetBkMode(oldBkMode);
  626.  
  627.     if(nullDC)
  628.         ReleaseDC(pdc);
  629. }
  630.  
  631. void CCalenCtrl::DrawSelectedDay(BOOL bSelected, const CRect& rcBounds, CDC *pdc)
  632. {
  633.     int oldBkMode;
  634.     CFont *oldFont;
  635.     COLORREF clrColor, oldColor;
  636.  
  637.     CRect cRect(rcBounds);
  638.  
  639.     BOOL nullDC = FALSE;
  640.     
  641.     if(pdc==NULL)
  642.     {
  643.         pdc = GetDC();
  644.         GetClientRect(cRect);
  645.         nullDC = TRUE;
  646.     }
  647.  
  648.     oldFont = SelectFontObject(pdc,m_dayFont);
  649.     oldBkMode = pdc->SetBkMode(TRANSPARENT);
  650.   
  651.     CBrush cBrush;
  652.     char day[4];
  653.  
  654.     // Determine the colors for brush and background
  655.     if(bSelected)
  656.     {
  657.         oldColor = pdc->SetTextColor(TranslateColor(GetForeColor()));
  658.         clrColor = TranslateColor(m_selectedDayColor);
  659.     }
  660.     else
  661.     {
  662.         oldColor = pdc->SetTextColor(TranslateColor(m_dayColor));
  663.         clrColor = TranslateColor(GetBackColor());
  664.     }
  665.   
  666.     if(cBrush.CreateSolidBrush(clrColor))
  667.     {
  668.         // Determine exactly what the day coordinates are, 
  669.         // fill the rectangle, and redraw the day text.  
  670.         CRect littleRect;
  671.         CTime time(m_year, m_Month, 1, 1, 1 ,1);
  672.         
  673.         int maxPos = (time.GetDayOfWeek()-1+m_Day-1) * 30;
  674.         int cx = maxPos % (7*30);
  675.         int cy = maxPos / (7*30) * 30;
  676.         
  677.         littleRect.SetRect(cRect.left+15+cx+3,cRect.top+60+cy+3, 
  678.             cRect.left+45+cx-2, cRect.top+90+cy-2);
  679.         pdc->FillRect(littleRect,&cBrush);
  680.  
  681.         // Draw the day number
  682.         sprintf(day, "%d", m_Day);
  683.         pdc->TextOut(littleRect.left+1, littleRect.top+1, 
  684.             day, lstrlen(day));
  685.     }
  686.     
  687.     pdc->SetTextColor(oldColor);
  688.     pdc->SelectObject(oldFont);
  689.     pdc->SetBkMode(oldBkMode);
  690.  
  691.     if(nullDC)
  692.         ReleaseDC(pdc);
  693. }
  694.  
  695.  
  696.  
  697. BOOL CCalenCtrl::SetDate(short month, short day, short year) 
  698. {
  699.     BOOL RetVal = FALSE;    
  700.  
  701.     if(month >= 1 && month <= 12)
  702.     {
  703.         if(day >= 1 && day <= DaysInMonth[month-1])
  704.         {
  705.             m_Month = month;
  706.             m_Day = day;
  707.             m_year = year;
  708.             InvalidateControl();
  709.             RetVal = TRUE;
  710.         }
  711.         else
  712.           ThrowError(CTL_E_INVALIDPROPERTYVALUE,
  713.               "Day is outside of allowable range");
  714.     }
  715.     else
  716.         ThrowError(CTL_E_INVALIDPROPERTYVALUE,
  717.             "Month is outside of allowable range");
  718.  
  719.     return RetVal;
  720. }
  721.  
  722. void CCalenCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
  723. {
  724.     COleControl::OnLButtonDown(nFlags, point);
  725.  
  726.     short day;
  727.     
  728.     if((day = HitTest(point))!=-1)
  729.     {
  730.         CRect NullRect(0,0,0,0);
  731.         DrawSelectedDay(FALSE,NullRect);
  732.         m_Day = day;
  733.         DrawSelectedDay(TRUE,NullRect);
  734.         FireSelect(day);
  735.     }
  736. }
  737.  
  738. short CCalenCtrl::HitTest(CPoint &point)
  739. {
  740.     short retval = -1;
  741.     
  742.     // Must be at least past the start of the days
  743.     if(point.y>60)
  744.     {
  745.         // Must be at least between the first and last day on width
  746.         if(point.x > 15 && point.x < (15+30*7))
  747.         {
  748.             CTime cTime(m_year, m_Month, 1, 1, 1, 1);
  749.             
  750.             // Calculate the row and the column
  751.             int row = (point.y-60)/30;
  752.             int col = (point.x-15)/30;
  753.             
  754.             int day = row*7+col;
  755.             day = day + 1 - cTime.GetDayOfWeek() + 1;
  756.             
  757.             // If the day is within the bounds, then return the value
  758.             if(day > 0 && day <= DaysInMonth[m_Month-1])
  759.                 retval = day;
  760.         }
  761.     }
  762.     
  763.     return retval;
  764. }
  765.  
  766.