void CaImMenu::MeasureItem (LPMEASUREITEMSTRUCT lpMeasureItemStruct) { MENUITEMINFO iInfo; GetMenuItemInfo (lpMeasureItemStruct->CtlID, &iInfo); CaImMenuItem* pItem = (CaImMenuItem*)lpMeasureItemStruct->itemData; CFont fntDef; LOGFONT lfDef; CClientDC dc (0); CFont* pFont = (CFont *)dc.SelectStockObject (ANSI_VAR_FONT); if (pItem->CheckStyle (AMIS_DEFAULT)) { CFont* pFnt = dc.GetCurrentFont (); pFnt->GetLogFont (&lfDef); lfDef.lfWeight = FW_BOLD; fntDef.CreateFontIndirect (&lfDef); dc.SelectObject (&fntDef); } if (pItem->CheckStyle (AMIS_BAR)) lpMeasureItemStruct->itemHeight = 4; else lpMeasureItemStruct->itemHeight = m_dwHeight; lpMeasureItemStruct->itemWidth = 25 + 8 + 8 + 2 + dc.GetTextExtent (pItem->GetText ()).cx; dc.SelectObject (pFont); if (pItem->CheckStyle (AMIS_DEFAULT)) fntDef.DeleteObject (); }
// determine size of a given cell based on actual font settings CSize CMiniCalendarCtrl::ComputeSize() { const int iXDaysSpaceFromBorder = 15; const int iHeaderSpaceForBorder = 15; const int iHeaderYSpaceForBorder = 3; const int iDaysXSpacing = 5; const int iDaysYSpacing = 2; CSize szReturn(0, 0); int iWidthByDays = 0; int iWidthByDaysOfWeekIndividual = 0; int iWidthByHeader = 0; int iHeaderHeight = 0; int iDaysHeight = 0; int iX; // allocate a DC to use when testing sizes, etc CClientDC* pDC = NULL; if (::IsWindow(GetSafeHwnd())) pDC = new CClientDC(this); else pDC = new CClientDC(AfxGetMainWnd()); ASSERT(pDC); if (!pDC) throw (new CMemoryException()); // get current font and save for later restoration CFont* pOldFont = pDC->GetCurrentFont(); // first, use days to determine width // NOTE: typically, most fonts use the same pixel sizes for all numbers, // but this is not mandatory and many "fancy" fonts change this. To deal // with this, I am calculating the width of all possible dates the control will display pDC->SelectObject(m_pFont); for (iX = 1; iX <= 31; iX++) { CString strTemp = "00"; strTemp += CCalendarUtils::LongToString(iX); strTemp = strTemp.Right(2); CSize szTemp = pDC->GetTextExtent(strTemp); if (szTemp.cx > iWidthByDays) iWidthByDays = szTemp.cx; if (szTemp.cy > iDaysHeight) iDaysHeight = szTemp.cy; } // make sure we also try it with the special days font pDC->SelectObject(m_pFontBold); for (iX = 1; iX <= 31; iX++) { CString strTemp = "00"; strTemp += CCalendarUtils::LongToString(iX); strTemp = strTemp.Right(2); CSize szTemp = pDC->GetTextExtent(strTemp); if (szTemp.cx > iWidthByDays) iWidthByDays = szTemp.cx; if (szTemp.cy > iDaysHeight) iDaysHeight = szTemp.cy; } // finish computation m_iDaysHeight = iDaysHeight; m_iIndividualDayWidth = iWidthByDays; iWidthByDays = (iWidthByDays * 7) + (iDaysXSpacing*6) + (iXDaysSpaceFromBorder*2); iDaysHeight = (iDaysHeight * 6) + (iDaysYSpacing*6); // next use days of week to determine width and height. here again, we test each variant pDC->SelectObject(m_pFont); int iWidthByDaysOfWeek = pDC->GetTextExtent("S").cx; if (pDC->GetTextExtent("M").cx > iWidthByDaysOfWeek) iWidthByDaysOfWeek = pDC->GetTextExtent("M").cx; if (pDC->GetTextExtent("T").cx > iWidthByDaysOfWeek) iWidthByDaysOfWeek = pDC->GetTextExtent("T").cx; if (pDC->GetTextExtent("W").cx > iWidthByDaysOfWeek) iWidthByDaysOfWeek = pDC->GetTextExtent("W").cx; if (pDC->GetTextExtent("F").cx > iWidthByDaysOfWeek) iWidthByDaysOfWeek = pDC->GetTextExtent("F").cx; int iDaysOfWeekHeight = pDC->GetTextExtent("S").cy; if (pDC->GetTextExtent("M").cy > iDaysOfWeekHeight) iDaysOfWeekHeight = pDC->GetTextExtent("M").cy; if (pDC->GetTextExtent("T").cy > iDaysOfWeekHeight) iDaysOfWeekHeight = pDC->GetTextExtent("T").cy; if (pDC->GetTextExtent("W").cy > iDaysOfWeekHeight) iDaysOfWeekHeight = pDC->GetTextExtent("W").cy; if (pDC->GetTextExtent("F").cy > iDaysOfWeekHeight) iDaysOfWeekHeight = pDC->GetTextExtent("F").cy; // finish computation iWidthByDaysOfWeekIndividual = iWidthByDaysOfWeek; iWidthByDaysOfWeek = (iWidthByDaysOfWeek * 7) + (iDaysXSpacing*6) + (iXDaysSpaceFromBorder*2); if (iWidthByDaysOfWeekIndividual > m_iIndividualDayWidth) m_iIndividualDayWidth = iWidthByDaysOfWeekIndividual; m_iDaysOfWeekHeight = iDaysOfWeekHeight; // next compute width and height of header (month name and year) // again, because of font variations we will use a 20 year window and // attempt the calculation with every month name pDC->SelectObject(m_pFontBold); for (int iYear = m_iCurrentYear-10; iYear <= m_iCurrentYear+10; iYear++) { for (int iMonth = 1; iMonth <= 12; iMonth++) { CString strTest = GetMonthName(iMonth); strTest += " "; strTest += CCalendarUtils::LongToString(iYear); if (pDC->GetTextExtent(strTest).cx > iWidthByHeader) iWidthByHeader = pDC->GetTextExtent(strTest).cx; if (pDC->GetTextExtent(strTest).cy > iHeaderHeight) iHeaderHeight = pDC->GetTextExtent(strTest).cy; } } // finish computation iWidthByHeader += (iHeaderSpaceForBorder*2); iHeaderHeight += (iHeaderYSpaceForBorder*2); m_iHeaderHeight = iHeaderHeight; // cleanup DC pDC->SelectObject(pOldFont); // destroy DC delete pDC; // NOW, adjust return size if needed // start with widths (these are easy at this point) int iTotalWidth = iWidthByHeader; if (iWidthByDaysOfWeek > iTotalWidth) iTotalWidth = iWidthByDaysOfWeek; if (iWidthByDays > iTotalWidth) iTotalWidth = iWidthByDays; if (iTotalWidth > szReturn.cx) szReturn.cx = iTotalWidth; // adjust heights int iTotalHeight = iHeaderHeight + iDaysOfWeekHeight + iDaysHeight + 12; if (iTotalHeight > szReturn.cy) szReturn.cy = iTotalHeight; m_szMonthSize = szReturn; m_bSizeComputed = TRUE; return szReturn; }